programowanieFrontend deweloper

Opisz mechanizm stwierdzania typów (Type Guards) w TypeScript i podaj przykłady ich użycia. Jakie jest główne wiodące atuty i jakie niuanse należy wziąć pod uwagę przy implementacji funkcji o niestandardowych stwierdzeniach typów?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Type Guards — to mechanizmy, które pozwalają na precyzowanie typu zmiennej w bloku kodu, w oparciu o niektóre kontrole (na przykład, za pomocą typeof, instanceof, lub specjalnych funkcji zwracających wyrażenia w postaci param is SomeType).

Główny atut — to bezpieczeństwo i eliminacja błędów wykonania dzięki kontroli typów w czasie kompilacji.

Przykład:

interface Fish { swim: () => void } interface Bird { fly: () => void } function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined; } function move(pet: Fish | Bird) { if (isFish(pet)) { pet.swim(); } else { pet.fly(); } }

Tutaj funkcja isFish — to niestandardowe stwierdzenie typu.

Niuanse:

  • Jakiekolwiek dodatkowe kontrole logiczne muszą być ściśle związane z typizowaniem.
  • Błędy w funkcjach stwierdzających typy mogą prowadzić do niewłaściwego określenia typów w czasie wykonania.

Pytanie podchwytliwe.

Pytanie: "Czy kompilator TypeScript zawsze polega tylko na zwracanej wartości funkcji guard, czy używa jakiejś analizy wewnątrz funkcji?"

Odpowiedź: Kompilator TypeScript opiera się tylko na sygnaturze zwracanego wyniku param is Type. To, co dzieje się wewnątrz funkcji guard, nie jest analizowane pod kątem poprawności implementacji.

Przykład (niebezpieczny błąd!):

function isString(x: any): x is string { return true; } // Kompilator będzie uważać, że to zawsze string, chociaż tak nie jest: if (isString(123)) { // tutaj x jest typu string, ale w rzeczywistości to liczba }

Przykłady rzeczywistych błędów wynikających z niewiedzy na temat subtelności tematu.


Historia

W projekcie z dzielonymi DTO pomiędzy frontendem a backendem zapomniano dodać rygorystycznej kontroli wewnątrz niestandardowego stwierdzenia typu. W rezultacie część danych była błędnie postrzegana jako właściwy typ, co prowadziło do awarii na kliencie przy próbie użycia brakującej właściwości.


Historia

Programista napisał stwierdzenie typu, polegając na opcjonalnym polu, jednak struktura danych mogła całkowicie nie mieć tego pola. W wyniku tego w typowym switch-case brakowało gałęzi, a kompilator nie wydawał ostrzeżeń — w czasie wykonywania występowały wyjątki.


Historia

W jednej z usług podczas przejścia na TypeScript polegano tylko na wbudowanych stwierdzeniach typów (typeof, instanceof). Przy zmianie prototypu obiektów podczas wykonania kontrole stawały się nieprawidłowe, co prowadziło do skomplikowanych błędów do debugowania w produkcji.