GGistDev

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

  • readonly on properties prevents reassignment.
  • as const freezes 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 + readonly for immutability
  • Use inference by default; annotate to clarify APIs and boundaries