od Podstaw
1 godz. 54 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.
Prawdopodobnie znasz mechanizm intellisense, czyli inteligentnego podpowiadania kodu przez edytor. Pisząc kod w TypeScript, tworzysz definicje typów dotyczących Twojej aplikacji. W ten sposób dostęp do definicji klas i właściwości obiektów masz właściwie na wyciągnięcie myszki. Wystarczy "hover" na funkcji aby uzyskać szczegółowe informacje, które pomogą Ci w pisaniu kodu. Oprócz tego otrzymasz również automatyczne podpowiedzi w trakcie dostępu do właściwości i metod. Nic tylko pisać kod!
Nie musisz przepisywać całego projektu. TypeScript stanowi nadzbiór JavaScriptu. Zatem cały Twój projekt jest z nim w 100% kompatybilny, a Ty możesz stopniowo dodawać definicje typów. Nawet nie będziesz wiedział kiedy typy pojawią się w całej Twojej aplikacji. To daje Ci również możliwość uczenia się TypeScriptu w trakcie jego wdrażania. W tym kursie opanujesz podstawy a później... sam zobaczysz!
Ten kurs został stworzony z myślą o programistach, którzy podstawy JavaScriptu mają już za sobą i chcą poznać zalety statycznego typowania oferowanego przez TypeScript. Na początku Kursu zaczynamy również od krótkiej powtórki najważniejszych elementów samego JS.
3.8+
W tej lekcji omówimy sobie tzw.
intersection oraz union types.
Co to dokładnie jest
pokażę Ci na przykładzie.
W jednej z poprzednich lekcji mówiliśmy sobie o string literal types.
Przypomnę tylko, że dzięki nim możemy
określać jaki dokładnie ciąg znaków może być przypisany do danej zmiennej.
Wspomniałem też o tym, że szczególnie przydatne są one wtedy, gdy wykorzystujemy
je razem z uniami, czyli właśnie z union type.
Konkretnie wygląda to tak: w tej sytuacji określamy, że wewnątrz tej
zmiennej może znajdować się string: medium lub large.
Dzięki temu zyskujemy tutaj coś na wzór typu
enum, a różnica polega na tym, że te wartości nie są mapowane do liczb.
Także jeżeli przypiszę do tej zmiennej wartość medium
wszystko jest w porządku, ale jeżeli
zdecydujemy się na mały rozmiar kawy to TypeScript powie nam że, nie jest to
możliwe ponieważ mamy do dyspozycji tylko dwa rozmiary.
Idąc teraz dalej, union type daje nam coś jeszcze. Mianowicie
czasem może zdarzyć się tak, że do jakiejś
zmiennej będziemy chcieli przypisać wartość jednego lub drugiego typu.
No bo jak dotąd określaliśmy ściśle jakiego typu musi być zmienna,
ale teraz wykorzystując union type możemy określić również drugi typ.
Dzięki temu tak długo, jak wartość przypisana do tej zmiennej będzie typu
number lub string, wszystko będzie w porządku.
Union type szczególnie sprawdza się w
przypadku funkcji, do których mogą trafić argumenty różnego typu.
Zatem zdefiniujemy sobie tutaj nowy typ i
dzięki zapisowi union type określimy, że zmienne tego typu mogą być tekstem lub liczbą.
Teraz tak utworzony typ możemy przypisać do parametrów funkcji.
Dzięki temu ta funkcja będzie akceptować
już zarówno tekst, jak i liczby, ale zwróć uwagę, że jej rolą będzie podwajanie
przekazanych wartości, więc będziemy zwracać tutaj wartość typu number.
W momencie, gdybyśmy chcieli teraz zwrócić podwojoną wartość to oczywiście mamy tutaj
błąd, który mówi nam o tym, że nie możemy mnożyć wartości typu string.
A w tej sytuacji faktycznie może okazać
się, że value będzie tekstem. W takiej sytuacji oczywiście musimy
zmienić zachowanie funkcji, w zależności od typu przekazanej wartości.
Zatem w sytuacji, gdy przekazana wartość jest tekstem, musimy zamienić ją na liczbę
no i oczywiście sprawdzić typ.
W przeciwnym razie po prostu zwracamy podwojoną wartość.
No i w tym momencie TypeScript
potwierdza, że wszystko jest w porządku, ponieważ odpowiednio weryfikujemy tutaj typ.
Kolejnym przydatnym scenariuszem union type
jest wykorzystanie w kontekście wartości null oraz undefined.
Mianowicie weźmy sobie tutaj deklarację funkcji,
która początkowo ma ustawioną wartość undefined.
Jeżeli teraz przekazalibyśmy ją do funkcji,
która przyjmuje wartości typu string, no to mielibyśmy tutaj problem.
TypeScript, w przeciwieństwie do innych statycznie typowanych języków, nie pozwala na
przypisanie wartości undefined i null do innych typów.
Wyjściem z takiej sytuacji jest zastosowanie union type.
Po prostu definiuję tutaj typ, który może być tekstem lub wartością undefined,
no i ustawiam go przy parametrze zmiennej.
Dzięki temu wszystko jest tutaj w porządku.
Jeżeli chodzi o union types w tym momencie jest to wszystko.
Przejdźmy teraz do intersection types.
Podczas gdy union typ pozwala nam na wykorzystanie jednego lub drugiego typu,
tak intersekcja pozwala nam na łączenie typów.
Wykorzystamy sobie tutaj interfejsy, ale na razie
się nimi nie przejmuj, ponieważ będziemy mówić o nich w kolejnych filmach.
W każdym razie mamy tutaj interfejs knife, który posiada jedną metodę slice.
Następnie mamy metodę scissors, który posiada metodę cut.
No i teraz na podstawie tych interfejsów
możemy stworzyć typ, który będzie dbał o to, aby obiekty wykorzystujące ten typ
posiadały właściwości takie jak slice i cut.
No i teraz możemy stworzyć metodę, która
będzie wykorzystywać narzędzia pasujące do naszego typu.
Wewnątrz niej wywołamy metody cut oraz slice.
Zatem wszystko będzie działać tak długo,
dopóki obiekt, który zdefiniujemy, będzie typu multiTool i jak widzisz od razu mamy
informację o tym, że musi on posiadać właściwości slice oraz cut.
Dopiero teraz tak przygotowany obiekt może zostać użyty w naszej funkcji.
No i faktycznie wszystko tutaj się zgadza.
Do wykorzystania zarówno interesekcji jak i
uni będziemy jeszcze niejednokrotnie wracać.
Tymczasem dziękuję Ci za uwagę i do usłyszenia w kolejnej lekcji.
String literal union types · 1 min
// String literal types
let coffeeSize: "medium" | "large"
coffeeSize = "medium"
coffeeSize = "small"Union type · 3 min
// Union Type
let stringOrNumber: string | number
stringOrNumber = 255
stringOrNumber = "max"
type doubleAnything = string | number
function double(value: doubleAnything): number {
if (typeof value === "string") {
return parseInt(value) * 2
}
return value * 2
}Null i undefined · 3 min
// Unknown values
type maybeValue = string | undefined
let valuefromDOM
function show(value: maybeValue) {
return value
}
show(valuefromDOM)Intersection types · 4 min
// Intersection types
interface Knife {
slice(): string
}
interface Scissors {
cut(): string
}
type multiTool = Knife & Scissors
function useTool(tool: multiTool) {
tool.cut() /*?*/
tool.slice() /*?*/
}
const swissArmyKnife: multiTool = {
slice() {
return "slice!"
},
cut() {
return "cut!"
},
}
useTool(swissArmyKnife)