What does Readonly<T> do?
1. What Readonly<T> does
Readonly<T>makes all properties of an object read-only - that is, they cannot be changed, redefined, or deleted after the object is created.
Example
interface User {
id: number;
name: string;
}
const user: Readonly<User> = {
id: 1,
name: "Tim",
};
user.name = "Max"; // Error: cannot change property "name"You can read
user.name, but you cannot change it. TypeScript throws an error at compile time, before the code runs.
2. How Readonly<T> works internally
The Readonly<T> type is implemented via a mapped type:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};Explanation:
keyof Ttakes all the keys of typeT;readonlyadds the "read-only" modifier;T[P]preserves the original property type.
3. How Readonly<T> differs from const
Great question, they are often confused. See the differences below.
| Feature | Readonly<T> | const |
|---|---|---|
| Applies to | a type (object, interface, generic) | a variable |
| Checked | at the property level | at the reference level |
| Protects | the object's internal fields | only the variable itself |
| Where it acts | in the type system (TypeScript) | at runtime (JavaScript) |
Comparison example
const user = { id: 1, name: "Tim" };
user.name = "Max"; // Allowed!
constdoesn't allow you to reassign the variableuser = ..., but you can change the object's fields.
But with Readonly<T>:
const user: Readonly<{ id: number; name: string }> = {
id: 1,
name: "Tim",
};
user.name = "Max"; // Error - the property is readonly
Readonly<T>protects the contents, whileconstprotects the variable itself (the reference).
Combined usage
You can combine const and Readonly for full protection:
const user: Readonly<{ id: number; name: string }> = {
id: 1,
name: "Tim",
};Now:
usercannot be reassigned (because ofconst);user.namecannot be changed (because ofReadonly).
4. What happens if you try to change a Readonly<T> property
TypeScript blocks the change at compile time - it throws an error like:
Cannot assign to 'property' because it is a read-only property.Example
interface Config {
port: number;
host: string;
}
const cfg: Readonly<Config> = {
port: 8080,
host: "localhost",
};
cfg.port = 3000; // Error: the property is read-onlyIn the compiled JavaScript this is not blocked at runtime (TypeScript removes the types), but the IDE and compiler won't let you make the mistake in your code.
5. Readonly for arrays
You can make an array immutable:
const nums: ReadonlyArray<number> = [1, 2, 3];
nums.push(4); // Error
nums[0] = 10; // ErrorYou can only read the elements, but not change the structure.
6. Deep immutability (Deep Readonly)
The regular Readonly<T> protects only the top level.
Nested objects remain mutable.
Example:
interface User {
id: number;
profile: {
name: string;
city: string;
};
}
const u: Readonly<User> = {
id: 1,
profile: { name: "Tim", city: "Kyiv" },
};
u.profile.city = "Paris"; // Allowed! (Readonly is top-level only)To forbid changes inside nested objects, use DeepReadonly:
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? DeepReadonly<T[P]>
: T[P];
};
const deepUser: DeepReadonly<User> = {
id: 1,
profile: { name: "Tim", city: "Kyiv" },
};
deepUser.profile.city = "Paris"; // ErrorSummary
| Question | Answer |
|---|---|
What does Readonly<T> do | Makes all properties of a type read-only (readonly) |
How it differs from const | Readonly protects internal fields, const protects the variable itself |
| What happens when trying to change it | TypeScript throws "Cannot assign to '...' because it is a read-only property" |
| Does it work deeply | No, only the top level (for deep protection, use DeepReadonly<T>) |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.