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

    ↑↓ ruch · ⏎ otwórz · esc zamknij

    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. Tab wcina; naciśnij Escape, a potem Tab, by wyjść fokusem.

    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

    Tę zagadkę rozwiązało jak dotąd mniej niż 5 osób. Rozkład pojawi się, gdy próbka będzie na tyle duża, by coś znaczyć.

    Gra na krótkim dystansie

    Najmniej znaków

    Nie ma jeszcze publicznych wyników.

    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ą.

    Wykorzystuje