Skip to content

Zawężanie typów w TypeScript wyjaśnione

Sposoby, w jakie TypeScript zawęża typ wewnątrz gałęzi, pogrupowane według techniki: wbudowane guardy, własne predykaty, funkcje asercji, unie dyskryminowane, równość i przepływ logiczny oraz zawężanie przez aliasy i odroczone. Każdy wiersz łączy technikę z przykładem w jednej linijce.

Zawężanie (narrowing) to sposób, w jaki TypeScript zamienia szeroki typ na węższy wewnątrz gałęzi kodu, dzięki czemu może udowodnić, że dostęp do właściwości jest bezpieczny. Każde sprawdzenie (typeof, in, predykat, dyskryminator) mówi kompilatorowi: od tego miejsca wartość jest bardziej konkretna. Techniki poniżej to roboczy zestaw.

Tabela referencyjna · 23 wpisy
23 of 23 rows
Wbudowane guardy
Zawęża typy proste: string, number, boolean i inne.if (typeof x === 'string') x.toUpperCase()
Zawęża do instancji klasy lub czegoś konstruowalnego.if (e instanceof Error) e.message
Zawęża, sprawdzając, czy właściwość istnieje na wartości.if ('id' in obj) obj.id
Zawęża dowolną wartość do tablicy; zawęża unię do jej członka tablicowego.if (Array.isArray(x)) x.map(f)
Własne guardy
Funkcja predykatowa, której zwracana wartość zawęża argument.function isUser(x): x is User { return !!x.id }
Predykat może zawężać do unii typów, nie tylko do jednego.function isKey(x): x is string | number
Predykat przecięciowy zachowuje typ wejściowy i dodaje do niego pola.function hasId(x): x is x & { id: string }
Funkcja asercji, która rzuca wyjątek, gdy x nie jest danym typem.function assertUser(x): asserts x is User
Unie dyskryminowane
Zawęża unię po wspólnym polu literalnym, przez switch lub if.type E = { kind: 'a'; a: number } | { kind: 'b'; b: string }
Każdy przypadek zawęża do jednego członka unii.switch (u.kind) { case 'a': u.a }
Zawęża unię bez tagu, gdy właściwość istnieje tylko na jednym członku.if ('b' in u) u.b
Każdy przypadek to warunek; dopasowany przypadek zawęża wartość.switch (true) { case typeof x === 'string': }
Gałąź default przypisuje do never, dowodząc wyczerpującej obsługi switcha.default: { const x: never = u }
Równość i przepływ
Usuwa null i undefined po sprawdzeniu równości.if (x === null) return; x.toFixed()
Usuwa wartości fałszywe (0, '', null, undefined, NaN).if (!x) return; // x is defined here
Prawdziwa właściwość w łańcuchu dowodzi, że wartość bazowa istnieje.if (user?.active) user.name
Asercja niepustości usuwa null i undefined bez sprawdzenia.x!.toFixed(2)
Definitywne przypisanie: deklaruje, że x zostanie przypisany przed odczytem.let name!: string; init()
Zawężanie obowiązuje wewnątrz gałęzi i po wczesnych returnach.if (!arr) return; arr.map(...)
Aliasy i odroczenie
Stała const z wartością logiczną trzymająca sprawdzenie zawęża wszędzie tam, gdzie jest testowana.const isStr = typeof x === 'string'; if (isStr) …
Zmienna const zachowuje swoje zawężenie w domknięciach, które ją przechwytują.const s = get(); if (s) use(() => s.length)
Od TS 5.4 zmienna let lub parametr zachowuje zawężenie w domknięciach po ostatnim przypisaniu.let n: string | null = get(); if (n) use(() => n.length)
unknown nie może być użyte, dopóki guard nie zawęzi go do rzeczywistego typu.if (typeof u === 'string') u.length