Inference and explicit boundaries

Objective

Distinguish inferred local types from annotated function contracts. This course assumes you can already write JavaScript functions, loops, arrays, and objects.

Learning objective

Distinguish inferred local types from annotated function contracts.

Explanation

TypeScript checks JavaScript before execution. A local initializer usually supplies enough information for inference; a function parameter needs a declared contract. Types disappear from emitted JavaScript, so a number annotation does not validate an incoming JSON value.

Keep annotations at public boundaries and let obvious locals infer their types. Strict checking catches incompatible assignments but does not prove an algorithm computes the right answer.

Runnable worked example

Compile this complete example with strict checking. The practice editor supplies the function calls; return a value rather than printing it.

function double(value: number): number {
  return value * 2;
}

const result = double(0);

Expected value of result:

0

Types document the boundary; the expression determines runtime behavior.

Common mistakes

Do not replace a failing check with any. Separate a compile-time guarantee from runtime input validation.

Guided practice

Explain each parameter and return type in the example. Predict its empty or boundary case before running it. Change one annotation to an incompatible type and read the compiler diagnostic; then restore it and change the implementation to create a behavioral bug. Explain why the two failures require different checks.

Independent practice

Recap

Distinguish inferred local types from annotated function contracts. Strict checking protects type relationships; explicit runtime checks protect external-data boundaries. Keep tests for behavior and non-mutation alongside both.