Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The readonly modifier in TypeScript is a compile-time constraint applied to properties within classes, interfaces, and type aliases that prevents reassignment of the property’s reference after its initial assignment. It enforces immutability at the property level during static type checking.

Syntax in Classes

When applied to a class property, a readonly field can only be initialized in two places:
  1. Inline at the point of declaration.
  2. Inside the class constructor.
Any attempt to reassign the property outside of these two contexts will result in a compiler error (TS2540).
class ServerConfig {
    readonly port: number = 8080; // Inline initialization
    readonly host: string;

    constructor(host: string) {
        this.host = host; // Constructor initialization (Valid)
    }

    updateConfig() {
        // this.host = "localhost"; // Error: Cannot assign to 'host' because it is a read-only property.
    }
}

Syntax in Interfaces and Type Aliases

The modifier can be prefixed to properties defining object shapes. Once an object literal is cast to or inferred as this type, the compiler restricts reassignment of those specific properties.
interface Entity {
    readonly id: string;
    createdAt: Date;
}

const user: Entity = {
    id: "uuid-1234",
    createdAt: new Date()
};

// user.id = "uuid-5678"; // Error
user.createdAt = new Date(); // Valid

Technical Characteristics

1. Shallow Immutability The readonly modifier only protects the binding (the reference) of the property. If the property holds a reference type (like an object or an array), the internal state of that object can still be mutated. It does not imply deep immutability.
class StateManager {
    readonly flags: string[] = ["init"];
    readonly metadata: { version: number } = { version: 1 };
}

const state = new StateManager();

// state.flags = ["ready"]; // Error: Cannot reassign reference
state.flags.push("ready");  // Valid: Mutating the array

// state.metadata = { version: 2 }; // Error: Cannot reassign reference
state.metadata.version = 2;         // Valid: Mutating the object property
2. Compile-Time Erasure readonly is strictly a TypeScript construct. It is completely erased during transpilation to JavaScript. It does not emit Object.defineProperty with writable: false, nor does it invoke Object.freeze(). Consequently, it provides zero runtime protection against reassignment. 3. Structural Typing Bypasses Because TypeScript uses structural typing, a readonly property can be bypassed if the object is aliased to a type that does not enforce the readonly modifier.
interface ReadonlyPoint {
    readonly x: number;
    readonly y: number;
}

interface MutablePoint {
    x: number;
    y: number;
}

const origin: ReadonlyPoint = { x: 0, y: 0 };
const reference: MutablePoint = origin; // Valid structural assignment

reference.x = 10; // Mutates the underlying object, bypassing the readonly constraint of 'origin'
  • Readonly<T> Utility Type: A mapped type that iterates over all properties of type T and applies the readonly modifier to them.
  • readonly Arrays/Tuples: Applied to array types (e.g., readonly string[] or ReadonlyArray<string>) to remove mutating methods like push, pop, and splice from the type definition.
Master TypeScript with Deep Grasping Methodology!Learn More