Readonly types describe intent, while Object.freeze protects a value at runtime.

readonly intent `Readonly<T>` prevents assignments in TypeScript, and `Object.freeze` shallowly freezes an object at runtime.

Readonly and Freeze

requestedVolume
freeze.ts
Replay: real traced execution (multi-file project)
type Settings = {
    maxVolume: number;
    theme: string;
};

function clampVolume(value: number, settings: Readonly<Settings>): number {
    return Math.min(value, settings.maxVolume);
}

const requestedVolume: number = 12;
const settings: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });
const finalVolume: number = clampVolume(requestedVolume, settings);

console.log(`theme=${settings.theme}`);
console.log(`volume=${finalVolume}`);
type Settings = {
    maxVolume: number;
    theme: string;
};

function clampVolume(value: number, settings: Readonly<Settings>): number {
    return Math.min(value, settings.maxVolume);
}

const requestedVolume: number = 7;
const settings: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });
const finalVolume: number = clampVolume(requestedVolume, settings);

console.log(`theme=${settings.theme}`);
console.log(`volume=${finalVolume}`);
type Settings = {
    maxVolume: number;
    theme: string;
};

function clampVolume(value: number, settings: Readonly<Settings>): number {
    return Math.min(value, settings.maxVolume);
}

const requestedVolume: number = 20;
const settings: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });
const finalVolume: number = clampVolume(requestedVolume, settings);

console.log(`theme=${settings.theme}`);
console.log(`volume=${finalVolume}`);
  1. requestedVolume ← 12, settings ← [object Object]

    7    return Math.min(value, settings.maxVolume);8}910const requestedVolume→ 12: number = 12;  //@requestedVolume=7, 2011const settings→ [object Object]: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });12const finalVolume: number = clampVolume(requestedVolume12, settings[object Object]);
  2. function clampVolume(value: number, settings: Readonly<Settings>): num…

    3    theme: string;4};56function clampVolume(value12: number, settings[object Object]: Readonly<Settings>): number {7    return Math.min(value12, settings.maxVolume10);8}
  3. finalVolume ← 10

    10const requestedVolume: number = 12;  //@requestedVolume=7, 2011const settings: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });12const finalVolume→ 10: number = clampVolume(requestedVolume12, settings[object Object]);1314console.log(`theme=${settings.themedark}`);15console.log(`volume=${finalVolume10}`);
    outputtheme=dark
    volume=10
  1. requestedVolume ← 7, settings ← [object Object]

    7    return Math.min(value, settings.maxVolume);8}910const requestedVolume→ 7: number = 7;11const settings→ [object Object]: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });12const finalVolume: number = clampVolume(requestedVolume7, settings[object Object]);
  2. function clampVolume(value: number, settings: Readonly<Settings>): num…

    3    theme: string;4};56function clampVolume(value7: number, settings[object Object]: Readonly<Settings>): number {7    return Math.min(value7, settings.maxVolume10);8}
  3. finalVolume ← 7

    10const requestedVolume: number = 7;11const settings: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });12const finalVolume→ 7: number = clampVolume(requestedVolume7, settings[object Object]);1314console.log(`theme=${settings.themedark}`);15console.log(`volume=${finalVolume7}`);
    outputtheme=dark
    volume=7
  1. requestedVolume ← 20, settings ← [object Object]

    7    return Math.min(value, settings.maxVolume);8}910const requestedVolume→ 20: number = 20;11const settings→ [object Object]: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });12const finalVolume: number = clampVolume(requestedVolume20, settings[object Object]);
  2. function clampVolume(value: number, settings: Readonly<Settings>): num…

    3    theme: string;4};56function clampVolume(value20: number, settings[object Object]: Readonly<Settings>): number {7    return Math.min(value20, settings.maxVolume10);8}
  3. finalVolume ← 10

    10const requestedVolume: number = 20;11const settings: Readonly<Settings> = Object.freeze({ maxVolume: 10, theme: "dark" });12const finalVolume→ 10: number = clampVolume(requestedVolume20, settings[object Object]);1314console.log(`theme=${settings.themedark}`);15console.log(`volume=${finalVolume10}`);
    outputtheme=dark
    volume=10