programowanieFrontend developer

Wyjaśnij mechanikę zawężania typów (Type Narrowing) w TypeScript. Jakie są sposoby na zawężenie typów zmiennych, w jakim celu się to stosuje?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Zawężanie typu (Type Narrowing) w TypeScript to proces, w którym kompilator "rozumie", że w danym fragmencie kodu, zmienna jednoznacznie ma bardziej konkretny typ, na podstawie warunków.

Typowe techniki zawężania:

  • Sprawdzenie za pomocą operatora typeof:
function example(x: number | string) { if (typeof x === 'string') { // x: string tutaj return x.toUpperCase(); } else { // x: number tutaj return x.toFixed(2); } }
  • Sprawdzenie za pomocą instanceof (dla klas):
if (dateObj instanceof Date) { // dateObj: Date }
  • Sprawdzenie na null i undefined:
function print(value?: string) { if (value != null) { // value: string console.log(value.length); } }
  • Sprawdzenie za pomocą "właściwości dyskryminacyjnych":
type Pet = { kind: 'dog'; woof: () => void } | { kind: 'cat'; meow: () => void }; function sound(pet: Pet) { if (pet.kind === 'dog') { pet.woof(); } else { pet.meow(); } }

TypeScript obsługuje również niestandardowe funkcje typu strażnika:

function isString(x: unknown): x is string { return typeof x === 'string'; }

Zawężanie sprawia, że sprawdzenia typów są bezpieczniejsze, a kod — bardziej niezawodny.

Pytanie z pułapką.

Czy można zagwarantować zawężanie typu przez zwykłe porównania (np. ==/===), i czy zawsze działa?

Odpowiedź: Nie. Nie we wszystkich przypadkach TypeScript rozumie typ z prostych porównań, szczególnie jeśli porównanie jest zbyt "niejasne" lub zachodzi przez pośrednie zmienne/właściwości. Aby zwiêkszanie często należy stosować wyraźne mechanizmy (typeof, instanceof, właściwości dyskryminacyjne i strażnicy typów).

Przykład:

function foo(x: number | string | null) { if (x) { // x: string | number, null już nie jest możliwy, ale zawężenie do konkretnego nie będzie } }

Historia

W dużym projekcie TypeScript warunek typu user.role == 'admin' nie zawęził typu danych, i wciąż było konieczne pisanie sprawdzeń dotyczących istnienia właściwości. Programiści niedoszacowali zasady zawężania, co doprowadziło do błędów "Cannot read property ... of undefined".


Historia

W aplikacji mobilnej funkcja przyjmowała albo obiekt, albo string. Poprzez pośrednie wywołanie funkcji zmieniającej typ, zawężenie nie miało miejsca, i na niektórych urządzeniach wystąpił błąd przy wywołaniu metody, która nie istniała dla stringa. Testy na rzadkich przypadkach nie powiodły się.


Historia

Podczas migracji kodu z JavaScript do TypeScript nie zaimplementowano swoich funkcji strażników typów, zakładając, że sprawdzenia właściwości zawsze zawężą typ. W rezultacie złożone obiekty z opcjonalnymi polami zachowały się nieprawidłowo, a w runtime wystąpiły nieprzewidywalne błędy dostępu do danych.