Skip to content

DeepReadonly type ​

Makes every property and array read-only, at every depth: a frozen configuration, a state snapshot that must not be changed in place.

ts
import type { DeepReadonly } from 'utils';

Signature ​

ts
export type DeepReadonly<T> = T extends (...arguments_: readonly never[]) => unknown
  ? T
  : T extends readonly (infer Item)[]
    ? readonly DeepReadonly<Item>[]
    : T extends object
      ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
      : T;

Parameters ​

NameDescription
TThe type to protect.

Example ​

ts
const DEFAULTS: DeepReadonly<Settings> = { chart: { series: [] } };

Tests ​

Line coverage: 0 %.

  • ✅ makes every depth read-only
  • ✅ keeps functions whole

Source ​

src/types/deep-readonly.ts (on GitHub)

Source code
ts
/**
 * Makes every property and array read-only, at every depth: a frozen configuration, a state snapshot that
 * must not be changed in place.
 *
 * @template T - The type to protect.
 * @example
 * const DEFAULTS: DeepReadonly<Settings> = { chart: { series: [] } };
 */
export type DeepReadonly<T> = T extends (...arguments_: readonly never[]) => unknown
  ? T
  : T extends readonly (infer Item)[]
    ? readonly DeepReadonly<Item>[]
    : T extends object
      ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
      : T;
Test file
ts
import type { DeepReadonly } from './deep-readonly';

describe('DeepReadonly', () => {
  it('makes every depth read-only', () => {
    expectTypeOf<DeepReadonly<{ a: { b: number[] } }>>().toEqualTypeOf<{
      readonly a: { readonly b: readonly number[] };
    }>();
  });

  it('keeps functions whole', () => {
    expectTypeOf<DeepReadonly<{ f(value: number): string }>['f']>().toEqualTypeOf<(value: number) => string>();
  });
});

Keywords: deep, readonly, types, type

Generated from the JSDoc of the sources.