Historia pytania:
TypeScript implementuje statyczną typizację, dlatego czasami konieczne jest jawne przekształcenie jednego typu na inny. Na przykład, gdy programista lepiej zna strukturę danych niż kompilator lub gdy trzeba pracować z typizowanym API, którego typy źródłowe nie pasują do oczekiwań. W tym celu używa się mechanizmu rzutowania typów, lub assertion typów.
Problem:
Rzutowanie typów (type casting) w TypeScript nie dokonuje żadnych przekształceń wartości na poziomie wykonania: tylko informuje kompilator "zaufaj mi". Może to prowadzić do błędów, jeśli wskazane rzutowanie nie odpowiada rzeczywistemu zawartości danych. Błędy pojawią się tylko w czasie wykonania, a kompilator ich nie wykryje.
Rozwiązanie:
W TypeScript są dwa składnie rzutowania typów: składnia przez kątowniki (przestarzała, niezalecana dla JSX) oraz składnia as (zalecana).
Przykład kodu:
// Składnia przez kątowniki (nie dla .tsx) let someValue: any = "Hello World"; let strLength: number = (<string>someValue).length; // Składnia przez as let strLength2: number = (someValue as string).length; // Rzutowanie typu obiektu (niebezpieczne!) interface Cat { meow(): void; } interface Dog { bark(): void; } let dog: Dog = { bark() {} }; let cat = dog as unknown as Cat; // można to zrobić, ale omija typizację!
Kluczowe cechy:
Czy assertion typu dokonuje automatycznego przekształcenia wartości w czasie wykonania, jak w C# lub Javie?
Nie, assertion typu tylko podpowiada kompilatorowi, że zmienna ma ten typ. Żadne przekształcenie wartości nie zachodzi — odpowiedzialność spoczywa w całości na programiście.
Czy można rzutować typ A na typ B bez wspólnej struktury?
TypeScript na to pozwoli (przez podwójne rzutowanie, na przykład any lub unknown), ale underminuje to bezpieczeństwo typów i może prowadzić do błędów podczas wykonania.
const a = 5 as unknown as string; // niebezpieczne!
Czy bezpieczne jest rzutowanie any na złożony typ?
Nie, any wyłącza sprawdzanie typów: rzutowanie any na inny typ jest możliwe, ale TypeScript nie będzie w stanie wykryć niezgodności, wszelkie błędy ujawnią się tylko podczas wykonania.
Programista otrzymuje obiekt z serwera bez sprawdzania struktury, rzutuje go na oczekiwany typ przy pomocy as SomeType i używa w logice biznesowej. Przy zmianie API lub błędzie po stronie serwera aplikacja pada w czasie wykonania, bez błędów na etapie kompilacji.
Zalety:
Wady:
Programista z wyprzedzeniem waliduje strukturę otrzymanego obiektu, wykorzystuje funkcję guard typu i tylko po udanej weryfikacji dokonuje assertion typu.
Zalety:
Wady: