Przejdź do treści
webtype.orgwebtype.orgDwanaście zagadnień · 5/12

    ↑↓ ruch · ⏎ otwórz · esc zamknij

    Zagadnienie 5 z 12

    Modyfikatory

    Modyfikatory to drobny druk typów mapowanych. Łatwo je napisać i łatwo subtelnie pomylić, bo domyślne zachowanie — ciche kopiowanie tego, co już było — wygląda identycznie jak nierobienie niczego.

    Mapowania homomorficzne dziedziczą modyfikatory

    interface Draft { title?: string; readonly id: number }
    
    // Mapping over bare `keyof T` preserves ? and readonly:
    type Copy<T> = { [K in keyof T]: T[K] }
    type Same = Copy<Draft>   // { title?: string; readonly id: number }
    
    // Mapping over a computed key set does NOT:
    type Flat<T> = { [K in keyof T | never]: T[K] }
    type Bare = Flat<Draft>   // { title: string; id: number }

    Mapowanie jest homomorficzne tylko wtedy, gdy zbiór kluczy to dokładnie `keyof T` dla parametru `T`. Wylicz zbiór inaczej — złącz, przefiltruj, przemianuj przez `as` — a wszystkie modyfikatory domyślnie przepadną.

    To zaskakuje przy pisaniu typu `Merge`: wynik traci opcjonalność z obu źródeł i nic o tym nie ostrzega.

    `-?` usuwa też undefined

    type T = { a?: string }        // a?: string | undefined
    type R = { [K in keyof T]-?: T[K] }
    // { a: string }  — not { a: string | undefined }

    Odjęcie modyfikatora opcjonalności robi dwie rzeczy naraz: klucz staje się wymagany, a z typu wartości znika `undefined`. Tę drugą łatwo przeoczyć — i zwykle właśnie o nią chodziło.

    Najczęstsza błędna odpowiedź

    // Intent: make everything optional.
    type Loose<T> = { [K in keyof T]: T[K] | undefined }
    
    // The key is still required — you must write { a: undefined }
    // rather than omitting it. Optional and "may be undefined"
    // are genuinely different properties.

    Rozszerzenie wartości to nie to samo co uczynienie klucza opcjonalnym, a testy dokładnej równości je rozróżniają. Jeśli chodziło o opcjonalność, `?` należy postawić po klauzuli klucza.

    Ćwiczenie

    Usuń `readonly` z każdej właściwości, a `?` zostaw w spokoju.

    Spróbuj

    1
    type Frozen = { readonly a: string; readonly b?: number }
    • Thaw<Frozen>
      { a: string; b?: number }

    Do zapamiętania

    Modyfikatory działają na właściwości, nigdy na wartości. A mapowanie, które w ogóle rusza zbiór kluczy, zapomina każdy modyfikator, którego nie kazano mu zachować.

    Ćwiczone w