Readonly<T>
Constructs a type with all properties of T set to readonly, preventing reassignment of properties after creation.
Definition
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};Examples
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 propertyinterface 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 timeinterface 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
Partial<T>Constructs a type with all properties of T set to optional, allowing you to provide only a subset of the properties.
Required<T>Constructs a type with all properties of T set to required, removing optional modifiers from every property.
as const assertionThe as const assertion marks a value as deeply readonly with the most specific literal types possible, preventing type widening.
More Mapping Types
Explore TypeScript Types
Browse our complete reference of 30 TypeScript utility types with definitions, examples, and explanations.