Techniki Zaawansowane
2 godz. 35 min · Typescript · Full-stack i Programowanie
Adam GospodarczykZacznijmy od tego, że JavaScript jest dynamicznie typowany. Oznacza to, że typy zmiennych mogą się zmieniać w czasie wykonywania programu, a my nie mamy nad nimi kontroli. A po co nam ta kontrola? Między innymi po to, aby przypadkowo nie dodać typu number do string lub przekazać do funkcji nieprawidłowe danych. Ogromną zaletą jest to, że o tego typu błędach dowiadujemy się już na etapie pisania kodu a nie dopiero w trakcie jego wykonywania... na produkcji.
TypeScript umożliwia stosunkowo prostą migrację istniejących projektów JavaScript. W kursie na przykładzie zostały omówione trzy strategie, dzięki którym jesteśmy w stanie dodać statyczne typowanie do istniejącego kodu. W procesie migracji najważniejsze jest to, że przepisywanie kodu jesteśmy w stanie uzależnić również od poziomu naszej wiedzy na temat TypeScriptu i stopniowo dodawać kolejne elementy.
Na pierwszy rzut oka można uznać, że TypeScript tylko dodaje nam pracy, wymuszając dodatkową konfigurację oraz opisywanie typów. Mało tego zwiększa barierę wejścia w projekt dla mniej doświadczonych programistów. Trudno temu zaprzeczyć ALE - korzyści płynące ze statycznego typowania które wpływają na zmniejszenie liczby błędów oraz wykrywanie ich nawet na poziomie pisania kodu, oszczędzają czas który normalnie poświęcilibyśmy na późniejsze debugowanie aplikacji. Poza tym zwiększenie stabilności aplikacji daje szerokie korzyści biznesowe, które wielokrotnie wynagradzają nam czas wymagany na pisanie dodatkowej składni.
JavaScript jest językiem dynamicznie typowanym. W trakcie wykonywania programu, zmienne mogą zmieniać swój typ a my nie zawsze mamy nad tym świadomą kontrolę. Tylko ... po co nam ta kontrola? Główną zaletą statycznego typowania jest to aby uniknąć sytuacji w których przypadkowo przypisujemy tekst do zmiennej która powinna zawierać liczbę lub sytuacji w której przekazujemy do funkcji nieprawidłowe dane. Taki rodzaj pomyłek generuje błędy odniesienia (eng. ReferenceError), które zatrzymują działanie skryptu i są momentami bardzo uciążliwe do wykrycia. Dzięki statycznemu typowaniu, jesteśmy w stanie wykrywać je na etapie pisania kodu.
TypeScript na przestrzeni ostatnich lat zyskuje ogromną popularność w społeczności programistów JavaScript i coraz częściej jest nieodłącznym elementem ofert o pracę. W przypadku firm nastawionych na rozwój rozbudowanych aplikacji JavaScript już teraz jest w zasadzie standardem. Biorąc pod uwagę fakt, że najnowsze frameworki (np. Nest.js) wykorzystują TypeScript domyślnie, nauka tej technologii ma ogromny sens w kontekście rozwoju jako programista. I ostatnim argumentem za tym aby wziąć TypeScript na poważnie jest to, że stoi za nim firma Microsoft a on sam rozwijany jest już niemal 10 lat.
Ten kurs został stworzony z myślą o programistach, którzy podstawy TypeScriptu mają już za sobą i chcą poznać jego zaawansowane techniki. Aby w pełni wykorzystać wiedzę z tego kursu, niezbędna jest również zaawansowana znajomość JavaScriptu a w szczególności jego elementów prowadzonych w wersji ES6+. Zdecydowanie polecamy przerobienie kursu Podstawowego TypeScript, który znajdziesz na eduweb, przed korzystaniem z tego materiału.
3.9+
Kontynuując temat ustawień pliku tsconfig.json pokażę
ci teraz ustawienia kompilacji z niektórych omówionych ustawień korzystaliśmy
już na przestrzeni tego kursu bądź poprzedniego ale teraz przyjrzymy się
im nieco bardziej w tym momencie znajdujemy się w pliku tsconfig.json
i mamy tutaj takie podstawowe ustawienia kompilacji najczęściej
wykorzystywaną przeze mnie opcją w tym kursie było ustawienie strict
domyślnie to ustawienie jest wyłączone więc musimy pamiętać o tym
aby ustawić jego wartość na true pierwszą rzeczą o której trzeba tutaj powiedzieć
to fakt że nie chodzi tutaj wyłącznie o to aby ustawić tryb strict w plikach
javascript w rzeczywistości ustawiając tą jedną opcję ustawiamy kilka
innych za jednym zamachem zobaczmy więc co to są za opcję
pierwszą z nich jest opcja noImplicitAny i ona
również domyślnie jest ustawiona na false co ona dokładnie oznacza ano
oznacza to że jeżeli jakaś zmienna z pomocą inferencji typów zostanie określona
na typ any no to typescript potraktuje to jako błąd w
praktyce możemy przejść do pliku app.ts no i utworzyć tutaj
funkcję jeżeli funkcja ta będzie przyjmować teraz jakiś argument i nie określimy jego
typu no to zwróć uwagę że typescript wyrzuca nam tutaj błąd i
właśnie ten błąd jest związany bezpośrednio z opcją noImplicitAny jeżeli
teraz ją zakomentuję i zapiszę plik informacja o błędzie zniknie
ale nadal mamy tu pewnego rodzaju ostrzeżenie mówiące że wykorzystanie
typu any nie jest raczej tutaj dobrym pomysłem ostatecznie
więc proces kompilacji się tutaj powiedzie ale my musimy być świadomi tego
że typescript nie będzie nas ostrzegał o tego typu sytuacjach zatem
przywracam teraz tą opcję następną opcją jest noImplicitThis
czyli kolejne ustawienie które broni nas przed tym
abyśmy nie skończyli z nieokreślonym typem this i aby to zobaczyć
utworzymy sobie teraz klasę będzie ta klasa User zawierająca jedną właściwość
ustawioną na sztywno oraz metodę zwracającą funkcję która
z kolei zwraca właściwość name tej klasy oczywiście gdyby metoda
add zwracała bezpośrednio właściwość name wszystko byłoby tutaj w porządku
ponieważ typescript samodzielnie jest w stanie określić typ this natomiast
w momencie gdy przechodzimy tutaj do kolejnej funkcji nagle ten kontekst jest
gubiony no i oczywiście moglibyśmy zamienić tą funkcję na funkcję
strzałkowo i wszystko byłoby tutaj okej albo alternatywnie moglibyśmy
tutaj określić typ this i właśnie o to abyśmy o tym nie zapominali dba
opcja noImplicitThis kolejnym ustawieniem wchodzącym w skład ustawienia
strict jest opcja alwaysStrict no i właśnie tutaj
mamy bezpośrednie nawiązanie do javascriptu i jego ustawienia use strict włączając
tą opcję mamy pewność że kompilator zawsze zadba o to aby tryb strict
javascriptu był włączony kolejną opcją którą aktywuje nam tryb strict jest
opcja strictBindCallApply czyli jak sama nazwa wskazuje
dotyczy ona metod BindCall oraz Apply konkretnie
zakomentuję ją teraz na chwilę i wrócimy do naszego piku app.ts w którym zdefiniuję
funkcję przyjmującą dwa argumenty zadaniem tej funkcji będzie powtórzenie
pierwszego argumentu czyli wiadomości podaną ilość razy no
i teraz jeżeli wywołamy sobie tą funkcję wszystko jest tutaj w porządku ale sytuacja
zmienia się nieco w momencie gdy wykorzystamy tutaj metodę apply i
jak wiesz w drugim parametrem metody apply jest tablica do której przekazujemy
wartości które mają zostać przekazane jako argumenty i problem
tutaj polega na tym że jeżeli teraz przekażemy tylko jeden argument no
to typescript w żaden sposób nie poinformuję nas o błędzie jeżeli jednak
wrócimy do pliku tsconfig i włączymy naszą opcję no to
teraz wracając do pliku mamy tutaj jasną informację o tym że przekazaliśmy
niewłaściwe argumenty w momencie gdy dodam drugi argument wszystko
jest tutaj w porządku możemy zahaczyć o jeszcze jeden błąd
który pojawił nam się tutaj typescript informuje nas o tym że
metoda repeat nie występuje w typie string a my wiemy że
jednak występuje więc co tutaj jest nie tak ano chodzi o
to że w pliku konfiguracyjnym możemy ustawić jeszcze właściwość
lib do której możemy przekazać opcje es6 dzięki
temu dołączamy tutaj dodatkową bibliotekę która zawiera rozszerzone informacje
o typach dzięki temu problem który mieliśmy tutaj już zniknął
i mało tego jeżeli chcielibyśmy odczytać teraz dostępne metody typu string no to
nie byłoby z tym problemu korzystając teraz
jeszcze z okazji podobna sytuacja może mieć miejsce z elementami związanymi
bezpośrednio z przeglądarką czyli jak widzisz teraz odwołuję się do obiektu document
i próbuję na nim wykonać metodę querySelector typescript
informuje mnie tutaj o błędzie i mało tego od razu sugeruję rozwiązanie
polegające na tym abyśmy w pliku konfiguracyjnym tutaj do tej tablicy
dopisali DOM dzięki temu dodatkowe informacje o
typach trafią już do typescriptu no i mamy tutaj kolejny błąd informujący
nas o tym że przekazujemy do metody from niewłaściwy parametr
tutaj naturalnie powinniśmy skorzystać z metody quarySelectorAll a
następnie przekazać do niej jakiś argument tak że pamiętaj o tym
że jeżeli chodzi o właściwość lib niemal zawsze warto dodać tutaj
przynajmniej te dwie biblioteki no ale wróćmy teraz do tematu ustawienia
strict bo kolejną opcją która włącza się razem z nim jest opcja
strictFunctionTypes no i teraz aby pokazać ci sens
tego ustawienia muszę utworzyć nową funkcję która jako argument będzie
przyjmować callback callback ten będzie wykonywany a do niego
w zależności od wylosowanej liczby będziemy przekazywać odpowiednio ciąg znaków
lub liczbę jeżeli teraz skorzystamy z naszej funkcji
i przekażemy do niej callback o następującym kształcie czyli jak widzisz
jest to callback spodziewający się typu string no to w momencie gdy
wykonamy tutaj console.log i odwołamy się do metody która jest dostępna wyłącznie
dla typu string no to efekt końcowy będzie taki że
raz na 50% przypadków otrzymamy błąd tylko tutaj muszę
zakomentować tą linię no i teraz faktycznie mamy tutaj błąd a
po zapisaniu pliku mamy odpowiedni wynik nie muszę chyba
podkreślać że wystarczy że tutaj mielibyśmy jakieś działania asynchroniczne które
pobierało by dane i zwracało różny typ no to mielibyśmy tutaj
bardzo paskudny problem no ale być może powiesz że przecież mamy
tutaj typ any więc dlaczego mamy się spodziewać że typescript poinformuje
nas tutaj o błędzie no problem polega na tym że nawet jeżeli zdefiniujemy
sobie tutaj dokładny typ tej funkcji a następnie ustawimy ten
typ dla naszego argumentu no to typescript nagle ucichnie a
nasz błąd dalej tutaj występuje w tym momencie jest okej teraz
znowu teraz znowu i znowu ale
niespodzianka błąd nadal występuje dopiero w momencie gdy
aktywuję tą opcję typescript poinformuję mnie o błędzie który
istnieje tutaj mianowicie callback który tutaj mamy nie jest zgodny
typem z callbackiem którego spodziewamy się tu wracając
teraz do pliku tsconfig.json czyli ścisłe inicjalizowanie właściwości
tutaj istotny jest jeszcze fakt że aby ta opcja działała musimy
ustawić jeszcze jedną czyli strictNullChecks teraz w momencie
gdy wrócimy do naszego pliku i zdefiniujemy sobie tutaj klasę to jeżeli
dodamy do niej właściwość i nie zainicjalizujemy jej bezpośrednio lub
na przykład w konstruktorze no to typescript będzie wyświetlał nam tutaj jasny
błąd mówiący o tym że nie możemy tak robić i dlaczego jest to ważne
abyśmy tego pilnowali ano dlatego że jeżeli utworzę teraz nową instancję
na podstawie tej klasy a następnie odwołam się do właściwości która
teoretycznie istnieje no to powinienem otrzymać tutaj błąd tylko
zakomentuję tą linię i jak widzisz faktycznie błąd istnieje
i gdybym nie ustawił tych dwóch ostatnich opcji to ten błąd widoczny
byłby dopiero w momencie wykonywania programu no a tego byśmy zdecydowanie
nie chcieli tym oto sposobem zakończyliśmy omawianie ustawienia
strict a konkretnie wszystkich opcji które się pod nim kryją teraz
mam jeszcze dla ciebie kilka wskazówek których nie będę tak dokładnie omawiał
mianowicie jedną z tych opcji jest noUnusedLocals czyli
zasygnalizowanie nam zadeklarowanych zmiennych których nie używamy w programie
podobnie możemy zrobić z parametrami funkcji tymczasem kolejną
całkiem przydatną opcją jest wymuszanie na nas dodawania słowa kluczowego
break do instrukcji warunkowej switch i tutaj pokażę
szybko na przykładzie o co w tym dokładnie chodzi mianowicie wyobraźmy sobie
tutaj sytuację w której mamy switch który w zależności od podanego
argumentu wyświetla nam inny console.log no i w tej sytuacji jeżeli
usuniemy tutaj słowo kluczowe break to typescript automatycznie
poinformuję nas o tym że jednak musimy to zrobić dzięki temu
wszystko jest tutaj w porządku no i tymczasem mam ostatnią opcję którą
chciałbym się z tobą podzielić jest to opcja która zabezpiecza nas przed tym
aby funkcje zwracały wartości niejawnie bo jak doskonale
wiemy nawet gdy funkcja nie posiada słowa kluczowego return no to domyślną
zwracaną z niej wartością jest wartość undefined w ten oto
sposób przeszliśmy w mojej opinii przez takie najbardziej przydatne opcje pliku
konfiguracyjnego typescriptu i na ten moment to już
wszystko dziękuję ci za uwagę i zapraszam do kolejnej lekcji