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+
W tej lekcji chciałbym przedstawić ci koncepcję jaką type guard
o niej już akurat wspomniałem przy okazji ograniczeń generycznych
natomiast tym razem chciałbym ten temat nieco zastrzeżyć jeżeli
chodzi o samą definicję type guard to mówi ona o tym że jest to mechanizm
umożliwiający zawężanie typów domyślam się że
na ten moment niewiele ci to mówi więc po prostu przejdźmy do przykładu zdefiniuję tutaj
funkcjię którą zresztą wykorzystaliśmy przy okazji organiczneń generycznych
której to zadaniem jest przekonwertowanie przekazanego tekstu bądź
też tablicy ciągów znaków w taki sposób aby zamienić małe
litery na wielkie zatem tutaj mamy jasną sytuację pokazującą
nam że jedna funkcja jest w stanie przyjąć dwa różne rodzaje danych i
oczywiście my musimy zrobić tak aby obsłużyć zarówno jeden jak i
drugi przypadek inaczej mówiąc musimy w jakiś sposób ograniczyć typ
przekazanych danych i zachować się adekwatnie do tego z jakim typem
mamy do czynienia to w jaki sposób możemy sprawdzić typ danych
już oczywiście wiemy wykorzystujemy w tym celu operator typeof
przekazując do niego nasz argument jestem w stanie sprawdzić czy jest on typu string i
tutaj zwracam twoją uwagę na wykorzystanie operatora ścisłego porównania
dzięki temu mamy pewność że jeżeli do naszej funkcji trafi string
będziemy mogli wykonać na nim operacje toUpperCase na
ten moment typescript informuje nas o tym że mamy tutaj błąd ponieważ w
niektórych przypadkach może zdarzyć się tak że nasza funkcja nie zwróci
żadnej wartości i swoją drogą to ostrzeżenie pochodzi bezpośrednio z
eslint w każdym razie możemy sobie poradzić z tym w następujący
sposób w momencie gdy przekazany argument nie będzie stringiem
to mamy w zasadzie pewność że będzie tablicą stringów dlatego
też bez przeszkód będziemy w stanie wykonać na nim operację map wystarczy
że na każdym elemencie tablicy wykonam metodę toUpperCase a następnie
połączę ją w jeden ciąg znaków teraz jeżeli wykonam tą funkcję
zarówno dla tablicy jaki ciągu znaków otrzymamy poprawny wynik no
i w zasadzie właśnie na tym polega cała koncepcja type guard czyli
po prostu dotyczy ona sytuacji w której możemy spodziewać się więcej niż jednego typu
i musimy w jakiś sposób obsłużyć te sytuacje jednym
ze sposobów jest wykorzystanie operatora typeof a drugim wykorzystania
operatora instanceof o nim akurat będziemy mówić w kolejnym
odcinku natomiast ja chciałbym pokazać ci teraz jeszcze kilka małych szczegółów
jednym z nich jest fakt że tutaj wykorzystałem instrukcję warunkową
if ale tak naprawdę nic nie stałoby na przeszkodzie jeżeli wykonał bym
tutaj instrukcję switch ona jak wiesz sprawdzi się tutaj szczególnie dobrze
gdybyśmy tych opcji mieli zdecyduj więcej wtedy zamiast pisać
wiele instrukcji warunkowych if zastępujemy je wszystkie jednym switchem
efekt działania tej funkcji jest oczywiście taki sam chciałbym
po prostu żebyś miał to na uwadze tymczasem korzystając jeszcze
z okazji chciałbym ci pokazać jeszcze jeden sposób tworzenia type
guard z wykorzystaniem operatora in to również pokażę
ci na przykładzie tworząc teraz dwie klasy będzie to klasa song
oraz klasa playlist zwróć uwagę że to co je różni to nazwa
właściwości tutaj mamy tytuł a tutaj nazwę i
teraz w momencie gdybyśmy napisali funkcję która miałaby odtworzyć jakieś
media i do niej będziemy mogli przekazać zarówno jeden utwór jak
i całą playlistę no to aby rozróżnić jeden typ od drugiego
możemy wykorzystać operator in sprawdzając po prostu czy
mamy tutaj właściwość title czy też nie w momencie gdy taka właściwość
znajduje się w naszym obiekcie mamy do czynienia z utworem w przeciwnym razie
będzie to playlista no i jesteśmy w stanie to teraz zweryfikować
tworząc nowy utwór a następnie przekazując go do funkcji
play faktycznie nie ma tutaj zaskoczenia ponieważ mamy właściwość
title i właśnie został wykonany ten fragment kodu oczywiście
w tym konkretnym przykładzie być może powiesz mi że takie sprawdzenie typu możemy
załatwić w nieco inny lepszy sposób i to właśnie pokażę ci w kolejnej
lekcji natomiast czasem może okazać się że po prostu faktycznie będziemy
mieć jakiś obiekt i będziemy chcieli sprawdzić czy mamy do czynienia z właśnie
takim a nie inym obiektem i wtedy będziemy mogli to
zrobić wyszukując jego właściwości jest to coś co zdecydowanie
warto mieć na uwadze chociaż tak jak powiedziałem w tym konkretnym przypadku akurat
powinien zadziałać nieco inny mechanizm i tym zajmiemy się za chwilę
zapraszam cię do kolejnej lekcji
upperAnything · 2 min
function upperAnything(data: string | string[]): string {
switch(typeof data) {
case "string": return data.toUpperCase();
default: return data.map(item => item.toUpperCase()).join('')
}
}
upperAnything(['a', 'b', 'c']); /*?*/
upperAnything('abc'); /*?*/classes · 3 min
class Song {
constructor(public title: string) {}
}
class Playlist {
constructor(public name: string) {}
}play() · 4 min
function play(media: Song | Playlist) {
if ('title' in media) {
return 'Play song!'
}
return 'Play playlist.'
}
const bestThemeEver = new Song('Game of Thrones Theme');
play(bestThemeEver); /*?*/