programowanieFrontend developer

Jak działa mechanizm typów literałów szablonowych (Template Literal Types) w TypeScript i do czego jest potrzebny?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania

TypeScript przez długi czas pozwalał na określanie typów literałów dla pojedynczych wartości ciągów lub liczb, jednak wraz z pojawieniem się literałów szablonowych pojawiła się potrzeba typizacji konkretnej struktury ciągów. Typy literałów szablonowych umożliwiają definiowanie typów opartych na szablonowym łączeniu ciągów, co zapewnia statyczną walidację struktury wartości ciągów.

Problem

Nie można sprawdzić zgodności ciągu z określonym formatem (na przykład 'user_42') za pomocą zwykłych typów string — są one zbyt ogólne. Bez typów szablonowych kompilator nie może zagwarantować, że ciąg będzie odpowiadał ściśle określonemu wzorcowi.

Rozwiązanie

Typy literałów szablonowych pozwalają na tworzenie złożonych typów ciągów w czasie kompilacji i zapewniają ścisłą kontrolę ich zgodności z określonymi szablonami.

Przykład kodu:

type UserId = `user_${number}`; function loadUser(id: UserId) { // ... } loadUser('user_123'); // poprawne loadUser('admin_123'); // błąd kompilacji

Kluczowe cechy:

  • Tworzenie typów ciągów na podstawie literałów złączeń
  • Obsługa kombinacji, zagnieżdżeń i manipulacji kluczami obiektów
  • Zwiększenie bezpieczeństwa typów dla identyfikatorów ciągów, URL i innych struktur

Pytania z haczykiem.

Czy można używać typów literałów szablonowych tylko z number/literal? Czy można używać własnych literałów ciągów w szablonie?

Można używać dowolnych typów literałów — ciągów, liczb, złącz:

type EventType = `event_${'click' | 'hover'}`; // event_click | event_hover

Czy można przekazać zwykły ciąg, gdy funkcja oczekuje typu literału szablonu?

Nie, jeśli typ wyraźnie oczekuje literału-szablonu, po prostu string nie zadziała:

function handler(type: `btn_${string}`) {} handler('btn_click'); // ok handler('button'); // błąd kompilacji

Czy typy literałów szablonowych działają z mapped types i keyof?

Tak, typy literałów szablonowych świetnie łączą się z mapped types i kluczami obiektów:

const colors = {red: 1, blue: 2}; type ColorKey = keyof typeof colors; type ColorClass = `color-${ColorKey}`; // color-red | color-blue

Typowe błędy i antywzorce

  • Użycie typu szablonu tam, gdzie pasuje dowolny string
  • Zbyt agresywne typy szablonowe, które nie pozostawiają elastyczności
  • Przypisanie typów do wartości runtime, które nie są kontrolowane przez kompilator

Przykład z życia

Negatywny przypadek

API przyjmuje identyfikatory w formacie 'user_XXX', funkcja nie jest typowana — można przekazać dowolny ciąg, co w przypadku błędu na serwerze powoduje błędy.

Zalety:

  • Brak ograniczeń co do wartości

Wady:

  • Zespół popełnia błędy, przekazując niewłaściwe ciągi; testy są powierzchowne

Pozytywny przypadek

Używany jest typ UserId = user_${number}, przed kompilacją gwarantowana jest poprawność argumentów funkcji i bezpieczne zapytania do serwera.

Zalety:

  • Zmniejszenie liczby błędów, ścisła walidacja typów
  • Poprawa autouzupełniania i czytelności kodu

Wady:

  • Wymaga aktualizacji typów szablonowych przy zmianie schematu danych