readonly Properties & Immutability

Lock individual fields against reassignment, and understand what readonly does not do.

Prefix a property with readonly and the compiler forbids reassigning it after construction. It is perfect for identifiers, configuration, and values that should be set once.

interface Account {
  readonly id: string;
  balance: number;
}
const acc: Account = { id: "a1", balance: 0 };
acc.balance = 100; // fine
acc.id = "a2";     // Error: id is readonly

It is shallow

readonly stops reassignment of the property itself, not mutation of what it points to. A readonly array reference can still be swapped if... actually no β€” but a readonly field holding an object lets you still mutate that object's inner fields. For deep immutability you nest readonly or use Readonly<T> / ReadonlyArray<T>.

Compile-time only

Like all types, readonly vanishes after compilation. It documents and enforces intent during development; at runtime the object is an ordinary, mutable JavaScript object.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • An application config object is typed Readonly<Config> so no module can accidentally overwrite a setting after startup.
  • A pure function accepts Readonly<Order> to signal it only reads, never mutates, the order it receives.
  • A React component uses readonly props to make the contract explicit that the component must not modify its inputs.

More examples

Readonly utility type

Readonly<Point> prevents mutation of x and y while spread creates a new mutable copy with the desired change.

Example Β· ts
interface Point { x: number; y: number; }

const origin: Readonly<Point> = { x: 0, y: 0 };

origin.x = 1; // Error: Cannot assign to 'x' because it is a read-only property

// Create a moved copy instead
const moved: Point = { ...origin, x: 5 };

Readonly in function parameter

Annotating the parameter as Readonly communicates that the function will not mutate the array or its items.

Example Β· ts
function totalPrice(items: Readonly<{ price: number }[]>): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

const cart = [{ price: 10 }, { price: 25 }];
console.log(totalPrice(cart));

Deep readonly with as const

as const applies deep readonly to nested objects, while Readonly<T> only applies shallowly at the top level.

Example Β· ts
const settings = {
  db: { host: 'localhost', port: 5432 },
  cache: { ttl: 300 },
} as const;

// settings.db.port = 3306; // Error: read-only
type Settings = typeof settings; // deeply readonly

Discussion

  • Be the first to comment on this lesson.
readonly Properties & Immutability β€” TypeScript | SoundsCode