Codectionary / Developer documentation / TypeScript

Readonly<T>

Readonly<T> constructs a new type where every property of T is marked readonly, preventing reassignment after the object is created. It is a shallow transformation - nested objects within a Readonly<T> are not automatically deep-frozen, only the top-level properties are protected from reassignment.

Syntax

Readonly<Type>

Examples

Preventing Property Reassignment

Using Readonly<T> to enforce immutability at the type level.

interface Point {
  x: number;
  y: number;
}

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

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

Readonly Is Shallow

A common gotcha - nested objects are not automatically protected.

interface Config {
  settings: { theme: string };
}

const config: Readonly<Config> = {
  settings: { theme: "dark" }
};

// config.settings = { theme: "light" }; // Error - top-level property is protected
config.settings.theme = "light"; // Allowed! Readonly<T> does not protect nested objects

Best practices

  • Use Readonly<T> for function parameters that should not be mutated by the function, to make that contract explicit and enforced
  • Remember Readonly<T> is shallow - use a deep-readonly utility type (not built into TypeScript by default) if nested immutability is genuinely required
  • Combine with as const for the most specific, fully-locked-down literal types on object literals
  • Use readonly on individual array/tuple types (readonly number[]) as an alternative to wrapping the whole structure in Readonly<T>

At a glance

Purpose
Static types for JavaScript
File extension
.ts ยท .tsx
Runs in
Compiled to JavaScript
Usually used with
JavaScript and its ecosystem

Specifications & further reading

Related TypeScript documentation