GGistDev

Constants in TypeScript

Modeling immutability with const, as const, and readonly utilities.

const variables

const prevents rebinding but not deep immutability.

const config = { base: "/api", retries: 3 };
config.retries = 5; // allowed (object is still mutable)

as const (const assertions)

Freezes literal types and marks properties/array elements as readonly.

const ROUTES = {
  home: "/",
  about: "/about",
  status: 200,
} as const;
// type: { readonly home: "/"; readonly about: "/about"; readonly status: 200 }

Works on arrays/tuples too:

const DIRECTIONS = ["up", "down"] as const; // readonly ["up", "down"]

Readonly<T> and readonly arrays

type ReadonlyUser = Readonly<{ id: number; name: string }>;
const users: ReadonlyArray<string> = ["a", "b"]; // no mutating methods

satisfies operator

Keep precise literals while ensuring a wider shape.

const settings = {
  mode: "prod",
  retries: 3,
} as const satisfies { mode: "prod" | "dev"; retries: number };

Object.freeze and typing

Object.freeze returns Readonly<T> at runtime but does not deeply freeze nested objects.

const frozen = Object.freeze({ a: { b: 1 } }); // a: Readonly<{ b: number }>

For deep immutability, model types with mapped types or use utility libraries.

Const enums (caveat)

const enum inlines values at compile time but can break interop/tooling. Prefer enum or union literals unless you control emit (preserveConstEnums: true).

Summary

  • const stops rebinding; use as const to preserve literals
  • Use readonly utilities for shallow immutability; model deep immutability via types