Blog
/
Co nowego w Typescript 5.5?
Nagłówek posta na Blogu
24.07.2024
~ 7 min

Co nowego w Typescript 5.5?

inne
ciekawostki
nowości
Typescript 5.5 przyniósł kilka świetnych usprawnień. Sprawdź dlaczego zrobił tyle szumu.

Siemka! Nie tak dawno oficjalnie wyszedł nowy Typescript, a konkretnie wersja 5.5, która przyniosła kilka naprawdę fajnych ficzerów, które zostały przedstawione w tym poście. Większość z nich dzieje się pod spodem, bez naszej ingerencji, ale uważam, że warto o nich wiedzieć ;) Miłego czytania!

1. Lepsza inferencja typów

Jak widzisz poniżej tworzymy naszą tablicę obiektów trailerParkBoys, do której przypisujemy jakieś dane. Następna w kolejności jest funkcja getTrailerParkBoy, która przyjmuje tablicę stringów names. Następnie na tablicy names robimy operację; mapujemy i filtrujemy wszystkie elementy, które są "undefined", a więc w naszej tablicy boys już nie powinno być żadnego elementu "undefined" prawda?

Inferencja w TS poniżej 5.5

No właśnie w TS poniżej 5.5 (wersja na screenie to 5.4.5) to nie prawda 😕. Widać to w kolejnych linijkach, gdzie próbujemy wywołać metodę "action" na każdym elemencie z tablicy boys, bo dla TS'a element boy może nadal być niezdefiniowany (mimo tego, że wcześniej odfiltrowaliśmy wszystkie niezdefiniowane elementy!).

Infer TS5.4.webp

Poprawa inferencji typów w TS 5.5

Ale tutaj wchodzi Typescript 5.5 cały na biało. 😎 Obecnie Typescript już nie krzyczy o prawdopodobnie niezdefiniowany element, obecnie typ jest poprawnie dedukowany i możemy bez problemu wykonywać metodę boy.action()

Infer TS5.5.webp

Dlaczego to tak?

Typescript 5.5 teraz automatycznie tworzy sobie w metodach takich jak .filter "guarda", czyli sprawdzenie, czy aby napewno element, który mamy na myśli jest odpowiedniego typu, a nie (w tym wypadku) undefined.

Tak jak na screenie poniżej, w zależności od wartości true lub false zachodzącego warunku nasz element jest oczekiwanym typem (w przypadku true) lub czymś innym, w wypadku false; w naszym przykładzie to "undefined".

Wartość true lub false wynika z rezultatu sprawdzenia, które odbywa się pod spodem (i wygląda tak jak zakomentowana funkcja isTrailerParkBoy na screenie poniżej)

const isSpecifiedType(value: WantedType | undefined): value is WantedType => .. 
(... is ...Typ oczekuje boolean)

WAŻNE działa tylko gdy bezpośrednio damy "undefined" jako możliwy typ

InferGuard.webp

Warunki kiedy to działa!

  1. Funkcja nie ma jawnie zdefiniowanego typu return lub bezpośredniego przypisania typu.
  2. Funkcja zawiera tylko jedną instrukcję return i nie ma ukrytych zwrotów.
  3. Funkcja nie modyfikuje swojego parametru.
  4. Funkcja zwraca wyrażenie typu boolean, które jest związane z uściśleniem typu parametru.

Przykład, gdy to nie zadziała:

function getClassroomAverage(students: string[], allScores: Map<string, number>) {
  const studentScores = students
    .map(student => allScores.get(student))
    .filter(score => !!score);

  return studentScores.reduce((a, b) => a + b) / studentScores.length;
  //     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // error: Object is possibly 'undefined'.
}

Ponieważ warunek !!score w metodzie .filter może być false w przypadku null, undefined (i rzeczywiście niepożądanych wartości), ale tak samo będzie false w momencie gdy score = 0

2. Zawężanie typów (Type Narrowing)

Wiele razy zdarzyło Ci się, że wszystkie znaki na niebie i ziemi wskazywały, że jakiś obiekt NAPEWNO posiada dany klucz, ale tak naprawdę edytor sypał błędy na lewo i prawo krzycząc, że PAAANIE, TU NIE MA TAKIEGO KLUCZA? Mi dosyć często, co sprowadzało się do fikołków w kodzie, dodawania guardów czy rzutowania typów, żeby uświadomić TS'owi jak bardzo się myli. Na szczęście to już tylko historia 😎

TS starszy niż 5.5 nie zawężał poprawnie typu podczas dostawania się do wartości w obiekcie

Jak widać poniżej w Typescript starszym niż 5.5, mimo próby dostania się do wartości rekordu obj po sprawdzeniu, że wartość istnieje i jest stringiem Typescript nadal rzucał błąd Object is of type 'unknown'.

Do tej pory musieliśmy sobie z tym problemem radzić inaczej, na przykład rzutując wartość ręcznie as TYP TS5.4-narrowing.webp

TS 5.5 poprawnie dedukuje typ

Jak widać poniżej w Typescript 5.5 zostało to poprawione, dzięki czemu po sprawdzeniu wartości obj[key] wiemy, że istnieje i jest typu string zatem jesteśmy w stanie się do niej bez problemu dostać za pomocą obj[key] i wywołać metodę stringa toUpperCase() TS5.5-narrowing.webp

3. Sprawdzanie typów w REGEX

Teraz RegExpy są walidowane! To świetna informacja, bo teraz każdy nadmiarowy, bądź urwany nawias będzie nam rzucał błąd. (aaa, z resztą, i tak nikt nie pisze regexpów ręcznie 👀)

REGEXP.webp

4. Importy typów JSDoc

Podejrzewam, że JSDoc nie jest jakoś niesamowicie często używany za sprawą tego, że Typescript sam w sobie "dokumentuje" pisany przez nas kod. Niemniej ja subiektywnie bardzo lubię tego typu "streszczenie" tego, czym dana funkcja, metoda, klasa się zajmuje i za co odpowiada.

Do brzegu; do tej pory byliśmy ograniczeni do typów prymitywnych, przepisywania typu, albo próby importu go z jakichś modułów.

Przed TypeScript 5.5, gdy próbowałeś importować typy z zewnętrznych plików w JSDoc w plikach JavaScript, często pojawiały się błędy w czasie wykonania (runtime). Było to spowodowane tym, że TypeScript traktował te importy jak rzeczywiste importy modułów, co prowadziło do problemów, gdy w rzeczywistości importowane były tylko typy, a nie całe implementacje. Ponadto Typescript za sprawą ograniczonych możliwości statycznego analizowania typów nie mógł dokładnie rozpoznać typów z zewnętrznych plików.

TS5.4 JSDOC.webp

W TS 5.5 możemy użyć słowa kluczowego @import aby zaimportować nasz typ tak jak robimy to normalnie.

TS5.5 JSDOC.webp

5. Zmienna configDir w tsconfigach

Usprawnienie głównie przydatne w projektach typu "monorepo", ale warto o nim wiedzieć. Możemy mieć bazowy plik tsconfig, który współdzielimy w kilku różnych miejscach. No i wszystko spoko, ale co, gdy trzeba na przykład przekompilować TS do danego folderu? Wtedy zaczyna się mały problem, bo choćby nasz "outDir" będzie wypluwał pliki wynikowe do folderu /dist (umownie nazwa dist), ale w miejscu, gdzie znajduje się nasz plik bazowy, a nie ten, który go rozszerza.

Z pomocą przychodzi nam nowa zmienna configDir, która sprawia, że ta ścieżka będzie w odniesieniu do pliku, który rozszerza, a nie bazowego. Czyli w wypadku na screenie będzie kompilować nasze pliki TS do folderu /front-dir/dist (a nie /dist).

Używamy tego w taki sam sposób jak zmienne w template stringu: "${configDir}/nazwa_folderu"; tak samo jak na screenie poniżej. ;)

TSConfig.webp

Podsumowanie

To są według mnie najważniejsze pozycje, które sprawią, że praca będzie o wiele przyjemniejsza. Zachęcam do wgryzienia się w pozostałe smaczki w tym wydaniu TS'a 🤓

Do następnego! ~ Bartek

Materiały źródłowe:

  1. https://devblogs.microsoft.com/typescript/announcing-typescript-5-5-beta/#easier-api-consumption-from-ecmascript-modules
  2. https://www.youtube.com/watch?v=ty8hPSzY5jQ

Bądź na bieżąco!

Zapisz się do mojego newslettera, aby otrzymywać najświeższe wiadomości i aktualizacje prosto na swoją skrzynkę mailową! Tak jak Ty, też nie przepadam za spamem - zapewniam, że moje wiadomości będą zawierać tylko najważniejsze informacje.
Emoji wykonujące gest dzwonienia.