Optional and readonly Properties in TypeScript
Learn how optional (?) and readonly properties work in TypeScript, how they differ, when to combine them, and how they keep object types safe and immutable.
Expected Interview Answer
An optional property (marked with '?') may be present or absent on an object, while a readonly property can be set once at creation but never reassigned afterward.
Optional properties let TypeScript accept objects that omit certain fields; when accessed, their type becomes 'T | undefined', so you must narrow before use. Readonly properties enforce immutability at compile time — the compiler rejects any reassignment after the object is built, though it does not deep-freeze nested objects at runtime. The two modifiers are independent and can be combined, as in 'readonly name?: string'.
- Models fields that may legitimately be missing
- Prevents accidental mutation of stable data
- Documents intent directly in the type
- Catches reassignment bugs at compile time
- Works with interfaces, type aliases and classes
AI Mentor Explanation
Think of a team sheet: the wicketkeeper slot is required, but the twelfth-man note is optional and often left blank. Once the toss is done, the batting order is readonly — the umpires lock it and no captain can quietly rewrite the sequence for that innings.
Step-by-Step Explanation
Step 1
Mark a field optional
Add '?' after the property name in an interface or type, e.g. 'age?: number', so objects may omit it.
Step 2
Handle the undefined case
Because optional access yields 'T | undefined', narrow with a check or use optional chaining and nullish coalescing before use.
Step 3
Mark a field readonly
Prefix the property with 'readonly', e.g. 'readonly id: string', to forbid reassignment after construction.
Step 4
Combine modifiers
Write 'readonly name?: string' when a field may be absent but must never be reassigned once set.
Step 5
Understand the limits
Readonly is compile-time only and shallow; nested object contents can still mutate unless separately protected.
What Interviewer Expects
- Correct syntax for '?' and 'readonly'
- Awareness that optional access produces 'T | undefined'
- Knowing readonly is compile-time and shallow
- Ability to combine both modifiers
- Practical narrowing of optional values
Common Mistakes
- Treating an optional property as always present
- Believing readonly deep-freezes nested objects
- Confusing 'readonly' with JavaScript's const
- Using '| undefined' when '?' is clearer for optionality
- Forgetting readonly is erased at runtime
Best Answer (HR Friendly)
“An optional property is one that an object is allowed to skip, marked with a question mark. A readonly property can be set when the object is created but not changed afterward, which helps catch accidental edits while writing code.”
Code Example
interface User {
readonly id: string;
name: string;
nickname?: string; // optional
}
const u: User = { id: 'u1', name: 'Ada' };
// u.id = 'u2'; // Error: Cannot assign to 'id' (readonly)
console.log(u.nickname?.toUpperCase()); // safely handles undefined
function greet(user: User): string {
return `Hi ${user.nickname ?? user.name}`;
}Follow-up Questions
- How does optional chaining help when reading optional properties?
- Is readonly enforced at runtime or only at compile time?
- What is the difference between readonly and const?
- How do the Partial and Readonly utility types relate to these modifiers?
- How can you make nested object properties deeply readonly?
MCQ Practice
1. What type does accessing an optional property 'age?: number' produce?
Optional properties may be absent, so their accessed type is the declared type unioned with undefined.
2. What happens if you reassign a readonly property after construction?
readonly is a compile-time check; the TypeScript compiler reports an error, though nothing prevents it once compiled to JS.
3. Which declaration is both optional and immutable?
'readonly name?: string' combines both modifiers: the field may be absent and cannot be reassigned once set.
Flash Cards
How do you mark a property optional? — Add '?' after the name, e.g. 'email?: string'; the object may omit it.
What does readonly guarantee? — The property can be set at creation but cannot be reassigned afterward (compile-time only).
Is readonly deep? — No — it is shallow; nested object contents can still be mutated.
Type of an optional property on access? — The declared type unioned with undefined (T | undefined).