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.
- Wyrażenie
Draft - Rozwija się do
{ readonly name?: string } - Wyrażenie
Ready<Draft> - Rozwija się do
{ name: string }
Usuń readonly i opcjonalność z każdej właściwości. Tutaj name jest wymagane i zapisywalne.
Definicja typu
type Draft = { readonly name?: string }
type Ready<T> = { -readonly [K in keyof T]-?: T[K] }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
1type 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
- #212Odtwórz PickPar 2
- #219Odtwórz PartialPar 2
- #226Odtwórz ReadonlyPar 2
- #235WybierzPoTypiePar 3
- #236GetteryPar 3
- #241Odtwórz RequiredPar 2
- #242ScalPar 3
- #246WpisyPar 4
- #247Pomiń po typiePar 3
- #249Opcjonalne, ale tylko tePar 3
- #256OdwróćPar 3
- #257Krotka na obiektPar 3
- #258Które klucze są opcjonalnePar 4
- #263Z wpisówPar 3
- #270Wszystkie wartości obiektuPar 3
- #274Zastąp klucze uniiPar 4

