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 niektórych sytuacjach chcemy utworzyć nowy typ na podstawie istniejących.
Takie czynności mogą dotyczyć np.
wybrania poszczególnych elementów istniejącego typu czy np.
jakiejś ich modyfikacji.
Przykładem może być chociażby dodanie atrybutów orbit Only
abyśmy takich czynności za każdym razem nie musieli wykonywać od podstaw.
Typ Script oferuje nam tzw.
u pliki DivX lub inaczej mówiąc Matt Gibbs i ta druga nazwa bardziej sugeruje że
chodzi tutaj o pewnego rodzaju malowanie typów.
Zobaczmy więc jak to wygląda w praktyce.
Zacznijmy więc od utworzenia pierwszego typu.
Będzie to interfejs opisujący jakiegoś użytkownika na jego podstawie tworzymy
nowy obiekt który oczywiście musi posiadać te dwie właściwości.
Teraz w związku z tym że w wielu sytuacjach chcemy unikać budowania
obiektów stworzono nową funkcję która właśnie przyjmie nasz nowy obiekt a
następnie zwróci nam jego zamrożone wersje.
Swoją drogą Podkreślam tylko że w tym miejscu dokonujemy tzw.
płytkiej zauważenia obiektów więc mieli to na uwadze.
Gdyby ten obiekt posiadał zamierzone
właściwości musielibyśmy podejść do tego w nieco inny sposób.
W każdym razie wykonując tę samą funkcję teoretycznie wszystko jest w porządku.
Dlaczego tak akurat jest pokaże Ci za chwilę.
A tymczasem zastanówmy się co właściwie byśmy chcieli a wracała ta nasza funkcja.
Zastanówmy się nad tym chwilę no bo
chcielibyśmy aby te poszczególne właściwości obiektu były ustawione jako
obiekt on i w związku z tym utworze teraz nowy interfejs który będzie określał
takiego zaangażowanego użytkownika a następnie ustawienie jego poszczególne
właściwości poprzedzające je słowem read only.
Więc teraz wystarczy że przy pisze ten interface.
No i znowu wszystko jest w porządku.
Pytanie jednak brzmi jak to się stało że jeden typ został przed nami sformowany w
długi i właściwie w ogóle tego tutaj nie widzimy.
Cały sekret odkrywa się tutaj w momencie gdy usunięte.
Nagle okazuje się że zadziałała tutaj infekcja typów czyli
domyślam się że chodzi nam tutaj o zagrożoną wersję tego obiektu.
Dlatego też wykorzystał tzw.
mapę TTIP o nazwie Deep online
dodając tutaj ten typ mogę teraz najechać na niego myszką aby zobaczyć definicję.
Okazuje się że mamy tutaj nowy typ wykorzystujący typ genetyczny a wewnątrz
niego wykorzystujemy operator kinowy oraz nowy operator in.
I ten właśnie operator sugeruje że mamy do czynienia z tzw.
market Times czyli malowaniem typu.
Zatem jak widzisz po prostu w tym miejscu
mamy do czynienia ze zdefiniowanego typem wewnątrz jednego z plików.
PIP to ostatecznie nic nie stoi na
przeszkodzie abyśmy taki typ zdefiniować sobie sami.
Spójrzmy jeszcze szybko na definicję tego typu tutaj mamy informację o tym że jego
zadaniem jest zamiana wszystkich właściwości typu genetycznego
w taki sposób aby były dostępne wyłącznie do odczytu.
Dlatego też wystarczy że utworzy teraz
nowy alias a następnie przekaże do niego typ genetyczny.
Teraz naszym zadaniem będzie przekierowanie przez wszystkie właściwości
tego typu a następnie poprzez ich słowem kluczowym hit online.
I teraz nasuwa się pytanie w jaki sposób dokonać operacji.
Wiemy już że aby uzyskać poszczególne właściwości konkretnego typu możemy
wykorzystać operator off a te poszczególne właściwości oznaczają my sobie literę P.
Więc teraz jedyne co powinniśmy zrobić to w jakiś sposób zasygnalizować że chcemy
tutaj testować po elementach i to możemy zrobić z wykorzystaniem słowa kluczowego.
No i teraz wystarczy że przekaże tylko
poszczególne właściwości przekazanego typu.
Ten zapis daje nam dostęp do poszczególnych właściwości przekazanego
typu T i każdy z nich zapisuje pod literą P.
Dlatego też w wyniku działania tej pętli
chcemy odwołać się do naszego typu a następnie do jego właściwości czyli w
ten sposób tworzyliśmy nowe właściwości które tym razem są już online.
Ale są to właściwości które pochodzą z tego typu.
I swoją drogą mógłbym wykorzystać ten
mechanizm do tego aby sprawić żeby te właściwości nie były tylko do odczytu
tylko na przykład po to żeby były opcjonalne i swoją drogą taki scenariusz
również jest całkiem popularny więc został przewidziany przez State Street.
Zatem teraz przejdźmy do drugiego typu o nazwie Pan Share.
Wyobraźmy sobie teraz sytuację w której mamy interfejs opisujący artykuł i taki
artykuł posiada swój tytuł treść oraz datę publikacji.
Następnie mamy funkcję która zajmuje się
tym aby zaktualizować ten artykuł na podstawie przekazanych danych.
Dlatego też wykorzystujemy tutaj interfejs
i wewnątrz tej funkcji dbamy o to aby zaktualizować poszczególne właściwości.
Teoretycznie wszystko jest tutaj w jak największym porządku ze względu na to że
jak otworzymy nowy obiekt a następnie przekażemy go do tej funkcji to.
Na problem jednak często pojawia się w
praktyce kiedy to Chcemy zaktualizować wyłącznie jedno pole i nie chcemy
przekazywać wszystkich właściwości naszego modelu.
W tej sytuacji oczywiście informuje nas o błędzie
ponieważ przekazujemy model który nie pasuje do naszego interfejsu i
jednocześnie też chcielibyśmy uniknąć tworzenia specjalnych interfejsów tylko po
to aby obsłużyć aktualizacje poszczególnych właściwości.
Dlatego też w tej sytuacji wystarczy że zastosujemy tutaj szalę
no i dzięki temu błąd które tutaj mamy znikną a wynika to wyłącznie z tego że z
pomocą tego map TTIP Dokonaliśmy tutaj poznania naszego oryginalnego typu.
W taki sposób aby dodać do jego
właściwości informację o tym że są opcjonalne.
Inaczej mówiąc wygląda to tak jakbyśmy powstawały tutaj znaki zapytania.
Różnica jednak w tej sytuacji polega na
tym że nie modyfikuje tutaj naszego oryginalnego typu.
Podobnie sprawa wygląda w sytuacji
gdybyśmy chcieli na podstawie istniejącego typu stworzyć typ który składa się
wyłącznie z kilku wybranych przez nas właściwości.
Takie coś jesteśmy w stanie osiągnąć wykorzystując matrycę o nazwie Ping.
Jak widzisz w pierwszej kolejności przekazujemy do niego oryginalne typ a
następnie nazwę właściwości jaka nas interesuje.
Tutaj naturalnie moglibyśmy skorzystać z Unią Tip i zresztą tak jak podpowiada mi
edytor moglibyśmy tutaj wybrać pozostałe właściwości.
Dzięki temu w ten sposób sklep wymaga ode
mnie podania nie tylko tytułu ale również właściwości content.
Swoją odwagą Możemy też podejrzeć
definicję tego typu i jak widzisz różni się on od pozostałych tym że wykorzystuje
tutaj słowa kluczowe Extended off i na tym etapie ostatnim Macht Type o
którym chciałbym teraz powiedzieć jest typ Record.
Aby go zrozumieć wyobraź sobie sytuację w której mamy typ określający zestaw danych
na temat danej podświetlane w naszej aplikacji.
Następnie mamy tutaj drugi typ zawierający unię z literami Tip zawierający
poszczególne podstawione w naszej aplikacji aby stworzyć nowy obiekt na
podstawie tych kluczy oraz tego typu konkretnie tutaj w pierwszej kolejności
przekazujemy String bądź unię z treningów czyli w tym przypadku będzie to ten typ a
następnie typ który chcemy przypisać do tych poszczególnych właściwości.
Oznacza to tyle że wewnątrz naszego obiektu mogą znajdować się właściwości
których klucz pokrywa się z którąś z tych wartości oraz sam typ tych właściwości
pokrywa się z typem który przekazaliśmy tutaj.
W tym przypadku jest to interfejs który
wymusza na obiekcie to aby posiadał właściwość Tito.
Jak widzisz na ten moment mamy tutaj błąd informujący nas o tym że dane które tutaj
pisaliśmy nie wypełniają naszego typu no i faktycznie jeżeli dodamy tutaj dwie
pozostałe właściwości wszystko zaczyna być w porządku.
Na tym etapie proszę Cię o to abyś zdał sobie chwilę na zrozumienie tego co tutaj
właściwie się dzieje i aby to wszystko było dla ciebie jasne najlepiej pobierz
kod źródłowy do tej lekcji i ubój po prostu pobawić się trochę tymi typami.
Gorąco zachęcam Cię również do tego abyś zapoznał się z definicją mi tych typów i
na ich podstawie spróbował zdefiniować własne typy.
Dzięki temu z całą pewnością Martinez prędzej czy później staną się dla ciebie
całkowicie jasne o ile faktycznie już tak nie jest.
Poza tym wszystkim gorąco zachęcam również do tego abyś zajrzał w dokumentację do
tego aby sprawdzić sobie pozostałe marki bez których nie będę omawiał w tym kursie
ponieważ wybrałem tylko te które w mojej opinii są najbardziej przydatne.
Natomiast znowu w ramach ćwiczeń i nauki dobrze jest podejrzeć jak wyglądają
definicje poszczególnych typów które mamy tutaj dostępne.
Link do tej strony znajdziesz oczywiście w zasobach do tej lekcji natomiast czasem ja
zachęcam Cię do obejrzenia kolejnego materiału do usłyszenia za chwilę.
User and ReadonlyUser · 1 min
interface User {
username: string
pin_number: number
}
interface ReadonlyUser {
readonly username: string
readonly pin_number: number
}freeze() · 1 min
const user1: User = {
username: "Adam",
pin_number: 1234,
}
function freeze(user: User): ReadonlyUser {
return Object.freeze(user)
}freeze2() · 3 min
function freeze<T>(obj: T): Readonly<T> {
return Object.freeze(obj)
}
const freezedUser = freeze(user)mapped types · 8 min
// Record mapped type
interface PageInfo {
title: string
}
type Page = "home" | "about" | "contact"
const x: Record<Page, PageInfo> = {
home: { title: "home" },
about: { title: "about" },
contact: { title: "contact" },
}