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 kontynuujemy temat typów i
poznamy również takie, które są charakterystyczne dla samego TypeScriptu.
W pierwszej kolejności mamy tablice, przy których definiowaniu musimy określić
jakiego rodzaju dane będą się w niej znajdować.
Notacja wygląda w następujący sposób, czyli
jak widzisz mamy tutaj typ oraz nawiasy kwadratowe.
W tej sytuacji wykorzystuję słowo kluczowe 'const', więc oczywiście mam tutaj od razu błąd
informujący mnie o tym, że muszę zmienną zainicjalizować. No i wszystko jest w porządku,
tak długo, dopóki w tej tablicy znajdują się liczby.
W momencie gdy to się zmienia otrzymujemy informację, że tak nie może być.
Tymczasem do definiowania tablic możemy
wykorzystywać jeszcze drugą notację, która zasadniczo generuje nam taki sam wynik.
Natomiast w praktyce zdecydowanie częściej wykorzystujemy właśnie ten.
Co ciekawe tutaj korzystamy z typu
'array', który w JavaScripcie w praktyce typem nie jest.
Idąc dalej, w momencie gdy pracujemy na
elementach tablicy, oczywiście ich typy nadal są uwzględniane.
Czyli jeżeli zadeklaruję sobie tutaj zmienną typu number, a następnie spróbuję
przypisać do niej element naszej tablicy to wszystko będzie w porządku.
Wydaję mi się, że to akurat jest jasne, ale
co w sytuacji, gdy w tablicy będziemy chcieli wykorzystać dane różnego typu.
Wtedy do gry wchodzi drugi rodzaj tablic, określane mianem tuple.
Jeżeli programujesz w innych językach z pewnością go kojarzysz.
W praktyce chodzi tutaj o tablice,
w których zarówno liczba elementów oraz ich typ jest z góry określone. Czyli tutaj mamy
tablicę, w której znajdzie się dokładnie string i wartość logiczna, dlatego tak długo
jak ten warunek zostanie spełniony wszystko będzie grało.
Ale już w momencie, gdy pojawi się tutaj inny typ lub np.
dodatkowa wartość, no to TypeScript upomni nas o tym, że tak nie może być.
Jeżeli chodzi o tablice to już wszystko i możemy przejść do obiektów.
Tutaj w przypadku TypeScriptu co prawda nie ma czegoś takiego jak np.
typ object, natomiast obiekty określamy w
następujący sposób. Po prostu jako typ przekazujemy strukturę obiektów oraz
informację o tym, jakiego typu będą jego poszczególne wartości.
No i wewnątrz takiej zmiennej możemy
przechowywać wyłącznie obiekty spełniające taką strukturę.
Oczywiście doskonale wiesz, że właściwością obiektu może być również funkcja.
Wtedy nazywamy ją metodą. Przy definicji
takiego obiektu musimy określić jakiego rodzaju informacje będzie zwracać
taka metoda. I swoją drogą mogę od razu
zainicjalizować ten obiekt w następujący sposób.
Jak widzisz mam tutaj znak równa się i otwieram nawiasy klamrowe.
Następnie TypeScript od razu informuje
mnie o tym, że brakuje mi tutaj wspomnianej metody.
No i tak długo jak ta metoda nie zwraca
odpowiedniego typu danych, będziemy mieć tutaj informację o błędzie.
Tutaj akurat chcemy zwrócić właściwość name, która oczywiście jest stringiem, więc
wszystko będzie okej. Musisz przyznać, że nie jest to wcale takie trudne.
Kolejnym i ostatnim typem w tej lekcji będzie typ Enum.
I ten typ również możesz kojarzyć z innych języków programowania.
A jeżeli jest inaczej to na jego temat musisz wiedzieć tyle, że jest to po prostu
zbiór nazwanych, określonych wartości liczbowych.
Taki typ definiujemy w następujący sposób.
Zwróć uwagę, że mamy tutaj słowo kluczowe enum,
następnie nazwę tego typu oraz nawiasy
klamrowe. Wewnątrz nich definiujemy nazwy poszczególnych elementów.
W tym przypadku są to rozszerzenia dokumentów tekstowych.
No i teraz powiedziałem, że jest to zbiór
nazwanych, określonych wartości liczb całkowitych.
Tylko gdzie te liczby?
A w momencie gdy będziemy odczytywać te
poszczególne wartości, otrzymamy właśnie liczbę.
Domyślnie są one numerowane od zera, dokładnie tak jak w przypadku tablic,
natomiast nic nie stoi na przeszkodzie abyśmy mogli na to wpływać.
Przykładowo: jeżeli tutaj dodamy wartość 3
to będę mógł odwołać się do tego elementu, powołując się właśnie na tę wartość.
Wtedy, jak widzisz, zamiast liczby otrzymałem nazwę tego elementu.
Warto jeszcze zwrócić uwagę na to, że jeżeli tutaj ręcznie podałem liczbę, no to
kolejny element również zmienił swoją wartość.
Tymczasem wróćmy jeszcze na chwilę tutaj, bo mamy nazwę tego elementu, którą również
możemy wykorzystać do tego, aby odwołać się do elementu.
Wtedy w odpowiedzi otrzymujemy znowu liczbę.
Na tym etapie wiemy już w jaki sposób odczytywać wartości numeralne. Warto
wiedzieć, że takie wartości możemy wykorzystywać również w przypadku funkcji.
Po prostu jako typ argumentu przekazuję tutaj nazwę naszego zbioru.
Dzięki temu taka funkcja będzie przyjmować
wyłącznie dane, które pochodzą z naszego zbioru.
I tutaj znowu mogę przekazywać je w taki
sposób lub po prostu odnosząc się do wartości liczbowej.
Idąc dalej elementy zbioru enum mogą przechowywać również wartości typu string.
Konkretnie wygląda to w następujący sposób.
Mało tego istnieje również możliwość określenia wartości w następujący sposób.
Jak widzisz mam tutaj prostą operację łączenia ciągu znaków.
Równie dobrze mógłby wykorzystać tutaj template string lub np.
wartość z jakiejś zmiennej.
W każdym razie do tych elementów znowu odwołujemy się w taki sam sposób,
przy czym musimy pamiętać o tym, że w tej
chwili nie posiadają one wartości numerycznej.
Ostatnią rzeczą jeżeli chodzi o typ enum są tak zwane const enum.
Są to po prostu definicje typu enum, poprzedzone słowem kluczowym const.
Różnią się one od poprzedniego typu tym, że
w momencie transpilacji, wartości zbioru enum zostaną potraktowane dosłownie.
Inaczej mówiąc znikną z pliku wynikowego.
Ale pozwól, że pokaże Ci to na przykładzie, aby wszystko było jasne.
Tak zdefiniowany zbiór możemy wykorzystać w funkcji. Przyjmuje ona argumenty pasujące
do tego zbioru a następnie wykorzystuje je w instrukcji switch.
W momencie gdy transpilujemy ten kod otrzymujemy następujący wynik.
Jak widzisz wartości, które zapisaliśmy tutaj oraz tutaj zostały zamienione na
wartości liczbowe tutaj oraz tutaj. W takiej sytuacji z jednej strony oszczędzamy na
rozmiarze bundle'a, ale z drugiej strony rekomendowane jest zachowanie tej
oryginalnej składni i aby upewnić się, że tak faktycznie się stanie,
wystarczy, że dodamy do naszego pliku tsconfing następującą opcję.
I teraz mamy pewność, że const enum zostanie zachowane w naszym kodzie. Tym ustawieniem
kończymy tę lekcję i słyszymy się za chwilę.
Typ Array · 1 min
// Array
const data: number[] = [1, 2, 3, "4"]
const genericData: Array<number> = [5, 6, 7]
typeof Array /*?*/
let randomNumber: number
randomNumber = genericData[2]Typ Tuple · 2 min
// Tuple
let setting: [string, boolean]
setting = ["darkmode", true]
setting = ["darkmode", true, 10]Typ Object · 3 min
// Object
let product: { name: string; price: number; count: number }
product = {
name: "Mentoring session",
price: 340,
count: 2,
}
const user: { name: string; getName(): string } = {
name: "Adam",
getName() {
return this.name
},
}Typ Enum · 5 min
// Enum
enum ExtensionType {
doc,
docx = 3,
pdf,
}
ExtensionType.docx /*?*/
ExtensionType[3] /*?*/
ExtensionType["pdf"] /*?*/
function setExtension(extension: ExtensionType) {
extension /*?*/
}
setExtension(ExtensionType.doc)
setExtension(3)
enum ExtensionTypes {
doc = "application/msword",
docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
pdf = "application/" + "pdf",
}
ExtensionTypes.docx /*?*/
ExtensionTypes[2] /*?*/const Enum · 6 min
// const Enum
const enum SubscriptionStatus {
active,
expired,
}
function getSubscriptions(status: SubscriptionStatus) {
switch (status) {
case SubscriptionStatus.active:
return ["(active subscriptions)"]
case SubscriptionStatus.expired:
return ["(expired subscriptions)"]
}
}
function getSubscriptions(status: SubscriptionStatus) {
switch (status) {
case 0:
return ["(active subscriptions)"]
case 1:
return ["(expired subscriptions)"]
}
}