TypeScript

Krzysztof Kempiński
Sep 7 · 11 min read
Image for post
Image for post

W ramach podcastu “Porozmawiajmy o IT” miałem okazję porozmawiać z Michałem Miszczyszynem o TypeScript.

Posłuchaj naszej rozmowy w wersji audio 🎧 👇

Cześć! Mój dzisiejszy gość to programista, start-uper, bloger, aktywista, a także prelegent i nauczyciel. Twórca bloga Type of Web. Na co dzień buduje aplikacje internetowe na stanowisku full stack JavaScript, współpracuje przede wszystkim z firmami ze Stanów Zjednoczonych za pośrednictwem X-Team. Autor książki TypeScript na poważnie. Moim i Waszym gościem jest Michał Miszczyszyn!

Cześć, Michał! Bardzo miło mi gościć Cię w podcaście.

Cześć, dziękuję bardzo za zaproszenie. Jest mi niezwykle miło i przyjemnie!

Przyjemność po mojej stornie. Skoro Michał jest autorem książki TypeScript na poważnie, to o niczym innym niż o TypeScript możemy dzisiaj sobie porozmawiać.

Standardowo jednak rozpocznę od pytania na rozgrzewkę. Czy słuchasz podcastów i jeśli tak, to jakich najczęściej?

Tego typu mediów jak YouTube albo podcasty oglądam bardzo mało. W zasadzie z polskich to tylko jeden taki trochę powiązany z nami branżowo to jest podcast Na podsłuchu od Niebezpiecznika. To jest w zasadzie jedyny, którego słucham regularnie.

Dobrze. To wobec tego zaczniemy może od takiego podstawowego pytania: czym jest TypeScript? Na jakie problemy odpowiada? Dlaczego w ogóle powstał?

TypeScript to jest — mówiąc jak jest napisane u nich na stronie, to jest typowana wersja JavaScript. Założeniem tego projektu było dodanie adnotacji typów do istniejącego kodu JavaScript przy zachowaniu jak największej kompatybilności. Celem tego jest to, aby kompilator mógł nam szybciej znajdować błędy niż w JavaScripcie.

Początkowo był to głównie projekt — tak mi się wydaje — stworzony dla osób, które pisały w C-Sharpie albo w Javie. Zresztą, TypeScript jest stworzony przez zespół od Microsoftu. Dzisiaj jednak już tak się rozwinęło, że świetnie można w nim także pracować na przykład pisząc funkcyjnie. W zasadzie powoli staje się takim branżowym standardem.

Chciałem Cię zapytać o tę adopcję. Sam co prawda znacznie mocniej siedzę po stronie backendu, ale też te różne rzeczy, te różne rzeczy, te różne tendencje, które się dzieją po stronie powiedziałbym frontendu do mnie docierają. I o TypeScript słyszę coraz częściej i coraz więcej. Dlatego chciałem Cię zapytać jak obecnie wygląda adopcja TypeScriptu.

Czy programiści JavaScript z chęcią korzystają w ogóle z tych ficzerów pod tytułem „Typy” i czy w najbliższej przyszłości na rozmowie rekrutacyjnej znajomość TypeScript będzie już wymagana według Ciebie?

Myślę, że absolutnie tak. Sam akurat może jestem w trochę wyjątkowej sytuacji, bo ja pracuję z TypeScriptem od wielu lat. Można powiedzieć, że byłem wczesnym adopterem, trochę też ewangelistą. Od samego początku bardzo wierzyłem w ten projekt. Tak się składa, że pracuję z nim od wielu lat, ale też zauważam, że dla mnie nie ma dla mnie ofert pracy, w których TypeScript nie byłby przynajmniej wspomniany. W zasadzie więc robi się to taki standard. Firmy, nawet jeżeli firmy aktywnie nie używają, to już wspominają o tym w ofertach pracy, b chciałyby używać, bo widzą w tym benefity.

Jeśli chodzi o adopcję — czy są jakieś badania, szacunki — jak to się ma do JavaScriptu? Czy ta adopcja występuje czy coraz więcej firm korzysta? Wiesz coś na ten temat?

Nie przytoczę ci żadnych liczb z głowy, ale moglibyśmy zajrzeć na przykład do ankiety Stack Overflow która jest co roku organizowana i tam zobaczyć. Wydaje mi się, że TypeScript mocno ostatnio rośnie!

Jasne. To pewnie będzie taki trend wznoszący, prawda? Coraz więcej o TypeScript się słyszy, więc należy przypuszczać, że ta adopcja będzie rosła. Co prawda takich — nazwałbym to, legacy projektach jeszcze będę chciał z tobą porozmawiać później. Domyślam się, że one pewnie zostaną — nie oczekuję, nikt pewnie nie oczekuje tego, że nagle cały JavaScript zostanie zastąpiony TypeScriptem, natomiast sądzę, że ta adopcja będzie rosła.

Wspomniałeś coś o Microsofcie, jeśli chodzi o tę firmę, która stoi za rozwojem języka. Chciałem cię zapytać o szczegóły tego, kto stoi za rozwojem, jak wygląda community, kiedy ta technologia się pojawiła? Czyli tak trochę z historii TypeScriptu!

TypeScript pojawił się — pierwsze, publiczne wypuszczenie miało miejsce 1 października 2012 roku, czyli prawie 8 lat temu. Co ciekawe, to właśnie niedługo po tym zacząłem używać TypeScripta do pierwszych projektów na studiach. W pierwszej pracy od razu też rzuciliśmy się na to rozwiązanie, bo wydawało mi się świetne, mimo tego, że było dosyć ubogie. Tak jak wspominałem -TypeScript został stworzony przez zespół Microsoftu, ale jest projektem open source na dosyć dobrej licencji, wolnej. Na licencji Apache 2.0. Jeżeli ktoś chce, to bardzo łatwo może stać się współautorem TypeScripta. Chociaż oczywiście kod samego kompilatora jest dosyć skomplikowany, więc bariera dojścia jest wysoka. Ale jest to projekt open source, więc w teorii każdy mógłby coś dodać od siebie.

To chyba takie dosyć nietypowe dla Microsoftu, prawda? Że projekt Open Source, dosyć dobrze wspierany od samego początku. Myślę, że nieczęsto to się zdarza — nie wiem, czy się ze mną zgodzisz?

Zgadzam się, szczególnie w 2012 roku — wtedy wydaje mi się, że nikt się nie spodziewał, że Microsoft pójdzie w open source. To był chyba jeden z ich pierwszych głośnych projektów, który był za darmo otwarty. Teraz już tego jest więcej — wtedy to naprawdę nowość!

Powiedziałeś, że byłeś takim early adopterem, ewangelistą również tej technologii. Jak wygląda community związane z tą technologią? Światowe i nasze, polskie?

To zależy, o co dokładnie pytasz. Jeżeli chodzi o szukanie pomocy w internecie, to nie ma z tym problemów. Jest na przykład discord oficjalny po angielsku, TypeScriptowy. Na GitHubie też można zadać mnóstwo pytań — tam z resztą bardzo ciekawe dyskusje się toczą — na GitHubie TypeScripta.

Jeżeli chodzi o polskie community, to wydaje mi się, że — nieskromnie powiem — napędzam je głównie ja. Na grupie TypeScript Polska na Facebooku i właśnie na discordzie moim. Ale zauważyłem też coraz więcej — w naszej społeczności pojawia się publikacji o TypeScript. Ostatnio czytałem blog kolegi, który opublikował kilka już artykułów „Kurs Type Scripta”. Widziałem też na YouTube, że kilku popularnych vlogerów wypuściło teraz szkolenie z TypeScripta. Wydaje mi się więc, że to jest świetny moment, żeby się tym tematem bardziej zainteresować, nawet jeżeli do tej pory stało się z boku.

Okej. Chciałbym teraz przejść do bardziej technicznych aspektów. TypeScript jest językiem typowanym statycznie, co oznacza, że typy są nakładane na zmianie w czasie kompilacji. Istnieje jeszcze obok — czy oprócz takiego typowania statycznego takie coś, co się nazywa silnym typowaniem.

Mógłbyś powiedzieć, czym te dwa sposoby się różnią? Jak to w praktyce wygląda po stronie TypeScriptu, czyli nadawanie i później pilnowanie typów?

TypeScript jest z założenia językiem statycznie i silnie typowanym. Te dwie cechy można dowolnie kombinować — są języki, które są statycznie lekko typowane, są silne, dynamiczne języki, więc to jest całkowicie ortogonalne pojęcie.

Z przykładów takich języków — na przykład statyczny silny będzie OCaml, właśnie TypeScript. Statycznie słaby będzie C i C++.

Co to oznacza? Statyczny to jest tak jak wspomniałeś, typy nadajemy w zasadzie w trakcie kompilacji, a w praktyce nadajemy je w czasie pisania kodu przy pomocy adnotacji albo korzystamy z tego, co kompilator potrafi się sam domyślić. Natomiast typowanie silne i słabe — słabe polega na tym, że w trakcie działania aplikacji w jakimś miejscu, na przykład zmienna o typie, który jest liczbą może być potraktowana jak ciąg znaków w jakichś szczególnych warunkach. I w JavaScriptcie to się dzieje cały czas. Jeżeli od stringa 12 odejmiemy stringa 2 to odejmiemy liczbę 10. I na tym polega mniej więcej typowanie słabe, że te typy tych wartości zmieniają się często w sposób, którego nie jesteśmy w stanie do końca przewidzieć albo byśmy się nie spodziewali.

Jeżeli chodzi o typowanie silne, to TypeScript stara się robić co może, żeby takim sytuacjom zapobiec. Czyli kompilator wykrywa w kodzie sytuacje, w których próbujemy dodać do siebie liczbę i stringa. Informuje nas o tym, że nie powinniśmy tak robić. Jeżeli rzeczywiście chcemy zsumować te dwie liczby, to żeby tego stringa zrzutować na liczbę bardzo jasno i wyraźnie.

Jak w praktyce wygląda to pilnowanie typów w TypeScript? Jak rozumiem — to jest etap, który pojawia się w procesie kompilacji? Czy są jeszcze jakieś możliwości, żeby runtimie to sprawdzać?

To jest świetne pytanie i ono cały czas powraca. Wiele osób mnie o to pyta i często też, kiedy mówię, że założeniem TypeScript nie jest sprawdzanie typów w czasie działania aplikacji. I wtedy bardzo często słyszę odpowiedź, że w takim razie ten projekt w ogóle nie ma sensu. Wydaje mi się, że takie założenie postawili sobie twórcy i jego się trzymają. To też jest całkiem spoko, bo istnieją biblioteki i inne rozwiązania, które możemy połączyć razem z TypeScript, żeby sobie zapewnić bezpieczeństwo zarówno w czasie działania aplikacji, jak i w czasie kompilacji.

Napisałem o tym w książce cały rozdział, przedstawiłem dwie takie biblioteki: zod oraz io-ts. Ogólnie sprowadza się to do tego, że piszemy sobie validatory czy deserializatory, w zależności, z jakiego środowiska ktoś pochodzi to te pojęcia mogą być mu znane. I cała magia polega na tym, że te biblioteki są tak skonstruowane, że tak dobrze integrują się z TypeScript, że na podstawie samego Validatora kompilator też potrafi wywnioskować typ. Sprawdza więc zarówno w czasie kompilacji, a potem ta biblioteka w czasie działania programu. Jest to niestety rzadko jeszcze używane w światku JavaScirptu — w każdym innym języku programowania, szczególnie backendowym wydaje mi się, z to jest standard, ze się serializuje i deserializuje dane, a nie tylko ufa, że są poprawne. Miejmy nadzieję, że u nas też to się niedługo zmieni.

Okej. Tym kluczowym pojęciem jest sprawdzanie kompatybilności typów. Chciałbym cię właśnie o ten aspekt w TypeScripcie zapytać. Na pierwszy rzut oka wydaje się to oczywiste, ale jakby spojrzeć tam trochę pod maskę, to takie oczywiste nie jest. Mógłbyś powiedzieć, jak wygląda właśnie definiowanie kompatybilności typów czy określanie ich w TypeScriptcie?

To jest wbrew pozorom bardzo skomplikowany temat. Przede wszystkim takie oczywiste rzeczy jak próba przypisania liczby do stringa — wiadomo, że ze sobą niekompatybilne, TypeScript od razu to wykrywa. Natomiast ciekawsze sytuacje dzieją się, kiedy próbujemy przypisać do siebie jakieś typy obiektów. Mówiąc krótko, jest to dość skomplikowane, ale przez większość czasu, kiedy używałem TypeScripta, w ogóle nie zwracałem na to uwagi. Dlaczego? Dlatego, że dla osób, które wcześniej pisały w JavaScripcie, większość tych zachowań TypeScripta jest bardzo intuicyjna. To znaczy -on pozwala nam robić takie rzeczy, które są powszechne w środowisku javascirptowym i są szeroko wykorzystywane. Raczej tego nie ogranicza, ale stara się jednocześnie pilnować, żebyśmy nie zrobili jakichś głupot.

Tutaj moglibyśmy jeszcze długo mówić o dziedziczeniu, o podtypach, jak one są ze sobą kompatybilne. O tym, dlaczego niektóre typy są kowariantne, a inne są kontrawariantne. Nie sądzę, żeby to był dobry temat na rozmowę taką na podcaście, bo to dużo łatwiej jest okazać mając kod przed oczami.

No to odsyłam do twojej książki wobec tego — dla osób, które chciałyby poszerzyć ten wątek.

Wobec tego — kiedy uważasz, że stosowanie TypeScript to już jest taki trochę overkill, sytuacja, w której nie wykorzystujemy tych podstawowych benefitów, tylko po prostu używamy języka, bo jest na niego jakiś hype.

Sam się często łapię na tym, że staram się coś otypować, mimo że nie będzie to miało żadnych zalet z biznesowego punktu widzenia. To znaczy — staram się napisać coś, co jest sztuką dla sztuki trochę. Jednak to bardzo rzadko — w większości sytuacji wydaje mi się, że TypeScript bardzo mocno nam pomaga w pracy i w odnalezieniu się w kodzie — szczególnie o roku, dwóch, gdzie często nie pamięta się, co się dzieje, a te typy bardzo pomagają.

Jasne, są takie momenty, gdzie to jest overkill — wtedy można po prostu dać sobie spokój i powiedzieć, że jednak pragmatyzm wygrywa. I to jest bardzo fajne w TypeScriptcie, bo on na to pozwala. To znaczy — TypeScript nie jest do końca poprawny. Jego system typów nie jest do końca poprawny. On pozwala robić haki — ale polegają na tym, że mówimy TypeScriptowi „Wiesz co, wiem co robię — olejmy ten temat i idźmy dalej”. I starcza nam na to pozwala, bo została stworzona z myślą o migracji z TypeScriptu i pracy w środowisku JavaScriptowym. To się bardzo fajnie sprawdza.

Myślisz, że są jakiekolwiek projekty pod względem wielkości, złożoności, ilości ficzerów, jakakolwiek heurystyk, a która mogłaby dać nam informację, że może ten typeScript to już jest trochę za dużo?

Nie chciałbym tego robić, bo to jest tak, że powiem, że w małych projektach nie ma to sensu, tylko że — jeżeli mały projekt odniesie sukces, to staje się szybko dużym projektem. I co wtedy? Wtedy mam masę długu technologicznego. Wydaje mi się, że w każdym większym projekcie niż coś, co piszemy do szuflady, używanie TypeScritpa może mieć sens.

Okej — bardzo dyplomatycznie wybrnąłeś! W porządku.

Czytając o TypeScriptcie, zauważyłem, że pozwala on na tworzenie takich dodatkowych plików z rozszerzeniem .d.ts, jeśli dobrze pamiętam. Chciałbym cię pytać czym one są, dlaczego musimy tworzyć dodatkowe pliki i w jaki sposób się z nich skorzysta?

Te pliki mają dwa zastosowania — pierwsze z nich to jest dodawanie typów do istniejącego kodu, napisanego w JavaScriptcie. Na przykład mamy sobie bibliotekę Lodash — ona jest napisana w JavaScriptcie, ale twórcy czy społeczność chciało dodać do niej typy. Zamiast refaktoryzować, przepisywać całą bibliotekę na TypeScripta, to stworzyli taki plik dts — w uproszczeniu o tej samej nazwie co plik Lodasha, w tym samym folderze i tam dodali same typy. Czyli deklaracje wszystkich funkcji i zmiennych, które Lodash eksportuje. W ten sposób kompilator TypeScripta, także edytory tak jak CS code albo WebStorm potrafią odczytać ten plik i traktować ten kod JavaScriptowy, tak, jakby on był napisany w TypeScriptcie, jakie by miał typy.

To jest jedno zastosowanie. Drugie, kiedy we własnym projekcie dodajemy plik dts to on służy do deklarowania typów, które mają być globalne. Co to oznacza? Kiedy piszemy coś w przeglądarce i chcemy z jakiegoś powodu powiedzieć, że na obiekcie window, czyli na obiekcie globalnym, który jest w przeglądarce, jest jakieś pole, to najprawdopodobniej stworzymy plik dts i tam dopiszemy to pole.

Czy w projektach, z którymi masz do czynienia to jest taka powszechna technika czy to jest może taka wisienka na torcie, dodatek, z którego zbyt często się nie korzysta w praktyce?

Powiedziałbym, że to jest wisienka na torcie. Dobrze to określiłeś. To nie jest coś, co jest nam potrzebne na co dzień, jeśli chodzi o pliki dts we własnym projekcie. Bez wątpienia każdy, kto używa TypeScripta będzie korzystał z plików dts zainstalowanych przez npm-a do bibliotek javascirptowych.

Powiedziałeś, że w JavaScriptcie są dosyć proste typy. Jakiś string, jakiś numer i tak dalej, które są oczywiste w działaniu i kompilator TypeScripta jest w stanie dosyć prosto sprawdzić, czy wywnioskować sobie, że próbujemy zrobić coś niewłaściwego.

TypeScript chwali się też istnieniem typów zaawansowanych, przykładowo warunkowych czy mapowanych. Mógłbyś chwilę opowiedzieć o tych właśnie zastosowaniach? Po co tego typu typy zaawansowane w TypeScriptcie zaistniały?

Jak sama nazwa wskazuje, one służą do opisywania typami sytuacji, w których potrzebujemy zawrzeć w samych typach jakąś logikę. Jeżeli chodzi o te typy zaawansowane, to mamy od takich prostych jak część wspólna albo unia typów. Możemy napisać, że coś jest tym lub czymś innym. Na przykład, że rola użytkownika to admin lub user i tylko te dwie opcje są.

Możemy też pójść do tak zaawansowanych typów, jak wspomniane przez Ciebie typy mapowane. Po co nam typy mapowane? Służą one do tworzenia nowego typu na podstawie innego, już istniejącego.

Przykładowo możemy sobie stworzyć typ — wyobraźmy sobie taką sytuację. Mamy aplikację, w której możemy — taki standardowy CRUD. Z aplikacji z frontendu możemy tworzyć użytkownika wysyłając post z użytkownikiem i dostajemy zwrot za stworzonego użytkownika również. Tylko chcemy napisać to w ten sposób, że dane, które są wysyłane przez nas z frontendu oczywiście są mutowalne, bo w jakiś sposób uzupełniamy te pola. Natomiast to, co dostajemy, zwrotkę, będzie tylko do odczytu. Response serwera jest niezmienialny. Czy powinniśmy tworzyć dwa typy, które właściwie zawierają te same pola, tylko jeden z nich jest niemutowalny? Nie! Możemy użyć typu mapowanego, stworzyć jeden typ user, a potem zmapować go tak, żeby wszystkie pola stały się typu read only. To taki pierwszy z brzegu przykład.

Jeżeli chodzi o te typy mapowane, to jest ich całe mnóstwo. Bardzo dużo jest też typów mapowanych już wbudowanych, takich pomocniczych — już wbudowanych w bibliotekę standardową TypeScripta. Przy pomocy typów mapowanych, a także w połączeniu z typami warunkowymi możemy na przykład też usuwać pola z typów. Możemy dodawać te pola do już istniejących obiektów. Jeżeli mamy obiekt, w którym część pól jest opcjonalna, a część jest wymagana, przy pomocy typów warunkowych i mapowanych możemy stworzyć sobie nowy typ, w którym będą wyłącznie pola opcjonalne albo wyłącznie pola wymagane.

To jest taka wisienka na torcie. Bardzo często jest wykorzystywana przez twórców typów do skomplikowanych bibliotek, Lodash czy Randa. We własnym kodzie trochę rzadziej.

👉 Czytaj dalej na: https://porozmawiajmyoit.pl/poit-079-typescript/

kkempin’s dev blog

Dev and life blog.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store