Porady od mentora

Jak zaprzyjaźnić się z TypeScript’em?

TL;DR

Wspomagaj TS’a poprzez zawężanie typów. Nie używaj any.

Twoje podejście

Często spotykam się z opinią, że "TypeScript znowu coś krzyczy", "znowu coś mu nie pasuje". Pomyśl o TypeScript’cie jak o swoim przyjacielu, który ciągle obserwuje twój kod. Nigdy się nie męczy i chętnie wyjaśni, co jest nie tak :) To od nas zależy w jaki sposób przyjmiemy “jego” uwagi 🙂

Dlaczego krzyczy?

TypeScript sprawdza typy statycznie, więc nie ma możliwości, by mógł sprawdzić Twój kod podczas runtime. Z tego powodu przy pisaniu kodu musimy zapewnić, że flow naszego kodu w żadnym przypadku nie pozwoli na taki błąd.

Jak o niego zadbać?

Po pierwsze, korzystaj z funkcjonalności oferowanych przez TS’a. Prawdopodobnie każdy programista korzystający z TS miał moment, w którym dla świętego spokoju użył any. Oznacza to mniej więcej "Ok, koleżko nie pilnuj tego, będzie git". Należy jednak pamiętać, że korzystając z any, wyłączamy funkcje oferowane przez TS i wracamy do starego dobrego JS. Oczywiście, może się zdarzyć, że naprawdę nie wiemy, co wpadnie do funkcji, ale TS oferuje specjalny typ - unknown - właśnie do takich przypadków.

Skoro już wiemy, że warto korzystać z funkcjonalności TS, to jak sprawić, by był dla nas mniej kapryśny? Możemy zawężać typy wykorzystać szereg guardów znanych z JS’a.

Basic guards
A co z typami złożonymi?

Tutaj mamy większe pole do manewru. Załóżmy, że mamy funkcje która przyjmuje jakiś obiekt, o którym wiemy tylko tyle, że będzie miał klucz id z wartością string. Wypadało by użyć typu genetycznego w tym miejscu, ale TS podpowiada, “Hej, a skąd wiesz, że tu będzie id?” Ano wiem, bo tak sobie skonstruowaliśmy nasze obiekty w apce. Tylko jak to zakomunikować? Poprzez zawężenie typu (paradoksalnie przez użycie słówka extends 😃).

Asserts functions i asserts condition

Dobrze, teraz okazuję się, że nasza funkcja przyjmuje dwa obiekty, które mają inne właściwości. W zależności od pola “isGoodBoy” określamy jaki to student.

Jak możemy sobie tutaj pomóc? Możemy wykorzystać assert functions lub assert conditions. Różnica jest taka, że jeżeli po wywołaniu assert function, kod jest dalej wykonywany to mamy gwarancję, że jest ustalonego przez nas typu. W przypadku assert condition, zwracamy boolean i na jego podstawie działamy w naszym kodzie. Uwaga! W tym momencie to my przejmujemy władzę i TS nie będzie o nic pytał, dlatego musimy być świadomi co robimy 🙂

Asercja i adnotacja typu

Jaka jest różnica pomiędzy tablicami zadeklarowanymi jak na screenie poniżej? W pierwszym przypadku używamy adnotacji typu, mówimy TS’owi “ziomuś pilnuj mnie, bo już trochę wypiłem i mogę się pomylić”. W drugim przypadku stosujemy asercję, przekazujemy TS’owi, żeby się odwalił i może nie jest idealnie, ale jesteś pewny, że typ jest odpowiedni. W praktyce powinniśmy unikać asercji, bo to trochę jak z any. Wyłączamy sobie naszego koleżkę.

Function type

TypeScript oferuje nam różne wbudowane typy. Studenci lubią ich nadużywać, ale okazuje się, że większość z nich nie różni się od any. Weźmy na przykład Function, rzadko kiedy nie wiemy jaka będzie funkcja. () ⇒ void, już dużo lepiej nam pilnuje typu.

Object i object?

Dostaliśmy, aż dwa typy obiektu, ale którego użyć? Object’em (z dużej litery) można otypować wszystko, nawet prymitywy!* Natomiast object (z małej) zawęża nam typ do obiektu rozumianego jako typ złożony (tablice, funkcje, klasyczne obiekty). To w końcu czego użyć do otypowania obiektu? Ja proponuję utility type - Record<Keys, Type>

*Tutaj zagadka dla Ciebie, czemu nawet prymitywy? Odpowiedzi prosimy pisać w komentarzu 🙂

Podsumowując

Jeśli nasz przyjaciel coś nam podpowiada, to nie denerwujemy się na niego, bo w 99% przypadków ma rację. Dzięki temu piszemy czytelniejszy kod, łatwiejszy do utrzymania, a mój ulubiony benefit to autocomplete! Nie ma nic lepszego dla leniwych devów niż samo uzupełnienie się kodu.

Dzięki!