Przejdź do treści
webtype.org#215 deep-readonly · par 4

Nr 215 · 23 lipca 2026 · Trudna

Głęboko tylko do odczytu

Zaimplementuj `DeepReadonly<T>`, aby każda właściwość na każdym poziomie stała się `readonly`. Funkcje muszą przejść nietknięte.

01

Spróbuj rozwiązać samodzielnie

Par 4

Zagadka

deep-readonly.ts
Podejście 1 z 4Jeszcze nie sprawdzone

Zastąp ??? — rozwiązanie sprawdzamy przypadkami poniżej.

Testy

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 }

Jak oceniamy test Dokładna równość typów, nie przypisywalność — przecięcie to nie to samo co spłaszczony obiekt.

Jak poszło innym

Nobody is counting yet. Score distribution and the gra na krótkim dystansie board arrive with accounts — until then your results stay on this device.

Archiwum
02

Rozwiązanie z komentarzem

Opublikowano 24 lipca 2026

Rozwiązanie

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

Najczęstsza błędna odpowiedź

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

Bez osłony na funkcje `() => void` pasuje do `extends object` i zostaje zmapowane. Typ funkcyjny nie ma własnych właściwości wyliczalnych, więc wynikiem jest `{}` — sygnatura wywołania przepada.

Linia po linii

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

    `never[]` w pozycji parametru akceptuje dowolną sygnaturę, bo parametry sprawdzane są kontrawariantnie. To bezpieczny sposób na powiedzenie „dowolna funkcja” bez użycia `any`.

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

    Modyfikator `readonly` dodawany jest podczas mapowania, a typ wartości wchodzi w rekurencję. Jeden typ mapowany załatwia obie sprawy.

Do zapamiętania

Gałęzie warunku sprawdzane są po kolei, więc węższe przypadki idą pierwsze. `extends object` jest szersze, niż się większości wydaje — tablice i funkcje też je spełniają.