iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

TS Readonly

The readonly modifier marks a property as set-once. TypeScript checks at compile time — JavaScript doesn't enforce it at runtime, but it catches plenty of bugs before they ship.

On a class field

TS
class Money {
    constructor(public readonly cents: number) {}
}

const m = new Money(1000);
// m.cents = 2000;   // ✗ Cannot assign to 'cents' because it is read-only.

On an interface / type alias

TS
interface Config {
    readonly host: string;
    readonly port: number;
}

const c: Config = { host: 'localhost', port: 5432 };
// c.host = 'other';   // ✗ error

ReadonlyArray and readonly tuple

TS
const days: readonly string[] = ['Mon', 'Tue'];
// days.push('Wed');   // ✗ error — no push on ReadonlyArray

const rgb: readonly [number, number, number] = [255, 128, 0];
// rgb[0] = 0;        // ✗ error

Readonly utility type

TS
type Config = { host: string; port: number };
type FrozenConfig = Readonly<Config>;
// equivalent to: { readonly host: string; readonly port: number }

"as const" makes things deeply readonly

TS
const STATUSES = ['paid', 'pending'] as const;
// type: readonly ['paid', 'pending']
// STATUSES[0] = 'oops';   // ✗

readonly vs const

constreadonly
Variable binding doesn't change.Property of an object doesn't change.
Statement-level.Class / interface member.
JS construct.TS-only modifier.
Tip: readonly is shallow — readonly users: User[] stops you reassigning the array but not mutating it. Use readonly User[] (note: outside the brackets) to make the array itself immutable too.

Example

Example
interface Config {
  readonly host: string;
  readonly port: number;
}
const cfg: Config = { host: 'localhost', port: 5432 };
// cfg.host = 'other';   // ✗ error
console.log(cfg);
Try it Yourself »

Exercise

Make every property of T readonly.

type Frozen = <T>;

Test yourself

Q1. readonly enforcement is…
Q2. For immutable arrays use…
Q3. "as const" makes a value…

Discussion

Loading…