Saltar al contenido
Hacer un objeto profundamente de solo lectura

    ↑↓ mover · ⏎ abrir · esc cerrar

    Patrones

    ¿Cómo evito mutaciones bajo el primer nivel en vez de congelar solo el tipo del objeto exterior?

    Conserva funciones, recorre arrays y mapea cada propiedad del objeto con el modificador readonly.

    La receta

    type DeepReadonly<T> =
      T extends (...args: any[]) => unknown
        ? T
        : T extends readonly unknown[]
          ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
          : T extends object
            ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
            : T
    
    type Config = {
      api: { url: string; retries: number }
      tags: string[]
      format: (value: number) => string
    }
    
    type FrozenConfig = DeepReadonly<Config>

    La compilación compila esto y comprueba cada resultado de abajo.

    Cómo funciona

    1. 01
      T extends (...args: any[]) => unknown

      Las funciones ya son valores invocables; mapear sus miembros destruiría la firma de llamada.

    2. 02
      { readonly [K in keyof T]: DeepReadonly<T[K]> }

      Cada propiedad se congela y su valor vuelve a pasar por la misma decisión.

    Lo que obtienes

    Dónde falla

    Es inmutabilidad de compilación, no `Object.freeze`. También trata instancias de clase como objetos estructurales, lo que puede exponer miembros de implementación; añade casos explícitos para integrados y clases en código de dominio.

    Conclusión

    Los modificadores recursivos necesitan reglas de parada. Trata funciones y objetos especiales antes de la rama general.

    Véase también

    Patrones