Mapping Types

Readonly<T>

Constructs a type with all properties of T set to readonly, preventing reassignment of properties after creation.

Definition

TypeScript
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

Examples

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

const origin: Readonly<Point> = { x: 0, y: 0 };
// origin.x = 5; // Error: Cannot assign to 'x' because it is a read-only property
Frozen Config
interface AppSettings {
  theme: string;
  language: string;
  notifications: boolean;
}

function freeze<T extends object>(obj: T): Readonly<T> {
  return Object.freeze(obj);
}

const settings = freeze({ theme: "dark", language: "en", notifications: true });
// settings.theme = "light"; // Error at compile time
Redux-style State
interface State {
  count: number;
  items: string[];
}

function reducer(state: Readonly<State>, action: { type: string }): State {
  switch (action.type) {
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    case "RESET":
      return { count: 0, items: [] };
    default:
      return { ...state };
  }
}

Common Use Cases

  • 1Immutable state in Redux-style architectures
  • 2Preventing accidental mutation of shared objects
  • 3Function parameters that should not be modified
  • 4Frozen configuration after initialization
  • 5Domain objects that represent value types

Understanding Readonly<T>

Readonly<T> creates a new type where all properties of T are marked as readonly. This means that once a value is assigned to a property, it cannot be changed. This provides compile-time immutability guarantees that complement runtime techniques like Object.freeze.

Immutability is a cornerstone of predictable software. In state management systems like Redux, the state should never be mutated directly—instead, a new state object is returned from each reducer. By typing state parameters as Readonly<State>, TypeScript will flag any accidental mutation at compile time, catching bugs before they reach production.

Readonly is also useful for function parameters. When a function receives an object it should not modify, marking the parameter as Readonly<T> communicates this contract clearly. If someone later adds code that tries to mutate the parameter, TypeScript will immediately raise an error.

For shared configuration objects, Readonly prevents different parts of the application from inadvertently modifying settings that other modules depend on. Combined with Object.freeze at runtime, you get both compile-time and runtime protection.

It's important to note that Readonly only applies to the first level of properties. If a property is an object or array, the contents of that nested structure can still be modified. For deep immutability, you need a recursive DeepReadonly type or use the as const assertion for literal values.

Related Types

More Mapping Types

Explore TypeScript Types

Browse our complete reference of 30 TypeScript utility types with definitions, examples, and explanations.