TypeScript

Readonly and Optional Properties in TypeScript

Readonly and optional properties (?) are essential when building immutable, flexible, and safe data models in TypeScript. Let’s dive deep and cover all use cases with examples.


Readonly and Optional Properties in TypeScript

When defining object shapes in TypeScript using type or interface, you can control mutability and flexibility of fields:

  • readonly → property can be assigned only once, cannot be reassigned later.
  • ? (optional) → property may be missing (not required).

1. Optional Properties (?)

Optional properties make object types flexible. If a property is marked with ?, it may or may not exist.

interface User {
  id: number;
  name: string;
  email?: string; // optional
}

const u1: User = { id: 1, name: "Alice" };        // ✅ email missing
const u2: User = { id: 2, name: "Bob", email: "bob@mail.com" }; // ✅ email present

Why use optional?

  • For API responses where some fields may not exist.
  • For UI props where some features are not always needed.
  • For progressive object construction.

2. Readonly Properties

A readonly property cannot be reassigned after initialization.

interface Config {
  readonly appName: string;
  version: number;
}

const cfg: Config = { appName: "MyApp", version: 1 };

cfg.version = 2;       // ✅ allowed
cfg.appName = "Other"; // ❌ Error: Cannot assign to 'appName' because it is a read-only property

Why use readonly?

  • To enforce immutability (avoid accidental changes).
  • For constants in configs, domain models, etc.
  • For React props, which must not be mutated inside components.

3. Combining Readonly and Optional

Properties can be both readonly and optional.

interface File {
  readonly id: string;   // must exist, immutable
  name?: string;         // optional
  readonly size?: number; // optional but immutable if exists
}

const file: File = { id: "abc123" };

file.name = "report.pdf";     // ✅ allowed
file.size = 500;              // ✅ allowed (first assignment)
file.size = 600;              // ❌ Error (readonly)

4. type vs interface with Readonly/Optional

Both type and interface support these modifiers:

type Car = {
  readonly vin: string;
  brand?: string;
};

interface Bike {
  readonly serial: string;
  model?: string;
}

5. Readonly Arrays and Tuples

TypeScript also supports readonly arrays and tuples:

const nums: readonly number[] = [1, 2, 3];

nums.push(4); // ❌ Error: Property 'push' does not exist
type Point = readonly [number, number];
const p: Point = [10, 20];

p[0] = 30; // ❌ Error: Cannot assign to index because it is a read-only property

6. Utility Types for Readonly and Optional

TypeScript provides built-in mapped types to transform properties:

Readonly<T> – make all properties readonly

interface User {
  id: number;
  name: string;
}

type ImmutableUser = Readonly<User>;

const user: ImmutableUser = { id: 1, name: "Alice" };
user.id = 2; // ❌ Error

Partial<T> – make all properties optional

interface User {
  id: number;
  name: string;
}

type PartialUser = Partial<User>;

const u: PartialUser = {}; // ✅ both optional

Combining

type ReadonlyOptionalUser = Readonly<Partial<User>>;

7. Practical Examples

(a) React Props

Props are usually readonly, and many are optional:

type ButtonProps = {
  readonly label: string;
  onClick?: () => void;
};

const Button = ({ label, onClick }: ButtonProps) => (
  <button onClick={onClick}>{label}</button>
);

(b) API Responses in Node.js

Sometimes an API may omit fields. You can reflect that:

interface ApiResponse {
  readonly id: number;
  data?: string;
}

const res: ApiResponse = { id: 101 }; // ✅
res.id = 102; // ❌ readonly

(c) Angular Component Input

Angular’s @Input props are essentially readonly, but often optional:

interface UserProfile {
  readonly id: string;
  name?: string;
}

@Component({ ... })
export class UserComponent {
  @Input() user!: UserProfile;
}

8. Comparison Table

ModifierMeaningCan reassign?Can omit?
NormalRequired, mutable✅ Yes❌ No
?Optional, mutable if exists✅ Yes✅ Yes
readonlyRequired, immutable❌ No❌ No
readonly ?Optional, immutable if exists❌ No✅ Yes

9. Best Practices

  • Use readonly for immutable fields like IDs, config constants, or React props.
  • Use ? for fields that may not exist (API data, UI props).
  • Use both when optional data should not be changed after being set.
  • Prefer utility types (Readonly, Partial) when transforming whole object types.

Conclusion:
readonly and ? make TypeScript expressive and safe. They let you describe real-world data models accurately — where some fields never change, and others may not even exist. Combined with utility types, they give you precise control over object structures.


Related posts
TypeScript

Literals in TypeScript: String, Number, Boolean, Template, and Compound Literals

Literals are one of the fundamental building blocks of TypeScript programming. They represent fixed…
Read more
TypeScript

Utility Types in TypeScript: Pick, Omit, Partial, Required, Readonly, Record...

✅ — Utility Types are one of the most powerful features of TypeScript, but also one of the most…
Read more
TypeScript

Complete TypeScript Tutorial Online: Master TypeScript in 2025

TypeScript has revolutionized modern web development by bringing static typing to JavaScript, making…
Read more