Type inference is TypeScript figuring out types automatically from context, so you don't have to annotate everything. It infers from initial values, return statements, and usage.
ts
let x = 10; // inferred: number
let s = "hi"; // inferred: string
const arr = [1, 2]; // inferred: number[]
const obj = { a: 1, b: "x" }; // inferred: { a: number; b: string }
Inference in functions and callbacks
ts
function double(n: number) { return n * 2; } // return inferred as number
[1, 2, 3].map(n => n * 2); // `n` inferred as number from the array — no annotation needed
This contextual typing is why callbacks rarely need parameter annotations — TypeScript knows map on a number[] passes a number.
let vs const widening
ts
let a = "hello"; // widened to string (let can be reassigned)
const b = "hello"; // narrowed to the literal type "hello"
const infers the literal type because it can never change; let widens to the general type. This matters for unions:
ts
const dir = "up"; // type "up"
let dir2 = "up"; // type string
When to annotate anyway
- Function parameters (can't be inferred).
- When inference is too wide/narrow (e.g. you want
stringnot the literal). - Empty containers:
const xs = []infersany[]— annotate asnumber[].
Mengapa ini penting
Inference keeps TypeScript code nearly as concise as JavaScript while staying fully typed.
Understanding when it kicks in (and when it widens) lets you annotate only where it actually helps.
