Saltar al contenido
webtype.orgwebtype.org#215 deep-readonly · par 4

    ↑↓ mover · ⏎ abrir · esc cerrar

    N.º 215 · 23 de julio de 2026 · Difícil

    Solo lectura profundo

    Implementa `DeepReadonly<T>` para que cada propiedad, a cualquier profundidad, sea `readonly`. Las funciones deben pasar intactas.

    01

    Intenta el puzle tú mismo

    Par 4

    Puzle

    deep-readonly.ts
    Intento 1 de 4Aún sin comprobar

    Sustituye ??? — tu solución se comprueba con los casos de abajo. Tab indenta; pulsa Escape y luego Tab para sacar el foco.

    Comprobaciones

    4
    • DeepReadonly<{ a: number }>
      { readonly a: number }
    • DeepReadonly<{ a: { b: string } }>
      { readonly a: { readonly b: string } }
    • DeepReadonly<string>
      string
    • DeepReadonly<{ f: () => void }>
      { readonly f: () => void }

    Cómo se juzga una comprobación Igualdad exacta de tipos, no asignabilidad — una intersección no es lo mismo que el objeto aplanado.

    Cómo le fue a todo el mundo

    Menos de 5 personas han resuelto este puzle hasta ahora. La distribución aparece cuando la muestra sea lo bastante grande como para significar algo.

    Juego corto

    Menos caracteres

    Aún no hay marcas públicas.

    Archivo
    02

    Solución comentada

    Publicado el 24 de julio de 2026

    La solución

    type DeepReadonly<T> = T extends (...args: never[]) => unknown
      ? T
      : T extends object
        ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
        : T

    El error más común

    type DeepReadonly<T> = T extends object
      ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
      : T

    Sin la guarda para funciones, `() => void` encaja en `extends object` y se mapea. Un tipo función no tiene propiedades enumerables propias, así que el resultado es `{}` — se pierde la firma invocable.

    Línea por línea

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

      `never[]` en posición de parámetro acepta cualquier firma porque los parámetros se comprueban de forma contravariante. Es la manera segura de decir «cualquier función» sin recurrir a `any`.

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

      El modificador `readonly` se añade durante el mapeo y el tipo del valor recurre. Un solo tipo mapeado hace ambas cosas.

    Para recordar

    Las ramas condicionales se prueban en orden, así que los casos más estrechos van primero. `extends object` es más amplio de lo que casi todo el mundo espera — arrays y funciones lo cumplen.

    Usa