Variables in TypeScript
Bindings, annotations, inference, and immutability strategies.
let, const, var
- const: cannot be reassigned (but object contents may still be mutable)
- let: block-scoped mutable binding
- var: function-scoped; avoid due to hoisting quirks
const port = 3000;
let counter = 0;
var legacy = "avoid";
Type annotations and inference
Annotate when it clarifies intent or when inference is insufficient.
let id: number = 1; // explicit
let name = "Ada"; // inferred as string
Readonly and as const
readonlyon properties prevents reassignment.as constfreezes literal types and makes array/tuple elements readonly.
interface Config { readonly apiBase: string; retries: number }
const cfg: Config = { apiBase: "/api", retries: 3 };
const dirs = ["up", "down"] as const; // readonly ["up", "down"]
// dirs[0] = "left"; // error
Destructuring with types
const user = { id: 1, name: "Ada" } as const;
const { id, name } = user; // id: 1, name: "Ada"
const tuple: [string, number] = ["age", 42];
const [label, value] = tuple; // label: string, value: number
Annotate when needed:
const [first, ...rest]: [number, ...number[]] = [1, 2, 3];
Scope and hoisting
let/const are block-scoped and not accessible before declaration (TDZ). var is hoisted; prefer let/const.
Narrowing through reassignment
Reassignments can widen or narrow types depending on annotations. Prefer narrow literal types via as const and satisfies.
Summary
- Prefer
const+readonlyfor immutability - Use inference by default; annotate to clarify APIs and boundaries