Menu

Template literal types w TypeScript: składnia i przykłady

Template literal types budują typy literałów string tą samą składnią z backtickami co template stringi w JavaScripcie: on${Capitalize<E>}. Poznaj składnię, mnożenie unii, Uppercase i Capitalize, wzorce takie jak ${number}px, gettery w mapped types i parsowanie stringów z infer.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Template literal type buduje typy literałów string tą samą składnią z backtickami co template string w JavaScripcie. `on${Capitalize<"click" | "focus">}` to typ "onClick" | "onFocus", obliczany przez kompilator:

Template literal types istnieją tylko w czasie kompilacji. Sprawdzają literały string i otypowane wartości, gdy piszesz kod, i nic nie dodają do wyjściowego JavaScriptu. Powyższa tabela handlerów używa Record, żeby wymagać jednej funkcji dla każdej nazwy.

Składnia

W backtickach piszesz dosłowny tekst i placeholdery ${...}. Placeholder zawiera typ, nie wartość: typ literału string, number, bigint albo boolean, ich unię albo jeden z szerokich typów string, number, bigint, boolean, null i undefined.

Placeholder z szerokim typem, takim jak string albo number, tworzy wzorzec: typ zostaje jako `hello ${string}` i przyjmowany jest każdy pasujący string. Placeholder ze skończoną unią, taką jak boolean, jest rozwijany na jej elementy.

Unie się mnożą

Przy kilku uniach wynikiem jest każda kombinacja:

Trzy rozmiary razy dwa odcienie dają sześć elementów. Liczba szybko rośnie: pięć placeholderów, z których każdy zawiera unię dziesięciu liter, dałoby 100 000 elementów, a TypeScript odmawia z komunikatem error TS2590: Expression produces a union type that is too complex to represent. Użyj szerokiego placeholdera, takiego jak ${string}, gdy nie potrzebujesz każdej dokładnej wartości.

Uppercase, Lowercase, Capitalize, Uncapitalize

Cztery wbudowane typy zmieniają wielkość liter w typach literałów string. Są intrinsic: zaimplementowane w kompilatorze, a nie napisane w TypeScript.

TypWejścieWynik
Uppercase<S>"hello world""HELLO WORLD"
Lowercase<S>"Content-Type""content-type"
Capitalize<S>"hello world""Hello world"
Uncapitalize<S>"UserName""userName"

Zmieniają tylko typy. Żeby zbudować odpowiadający im string w czasie wykonania, nadal wywołujesz toUpperCase() albo sam wycinasz i zamieniasz pierwszą literę, a potem mówisz TypeScriptowi, że wynik ma dokładny typ:

as jest potrzebne, bo toUpperCase() ma w typach zwracać zwykły string. Wywołujący widzą sygnaturę funkcji, więc capitalize("report") ma typ literału "Report".

Wzorce stringów: ${number}px i podobne

Typ wzorca przyjmuje każdy string o danym kształcie. Przydaje się przy wartościach CSS, identyfikatorach i kluczach ze znanym prefiksem:

${number} przyjmuje każdy string, który JavaScript odczytuje jako liczbę, a to więcej, niż się wydaje: "-3px", "1e3px" i "0x10px" przechodzą sprawdzanie typów. Traktuj te wzorce jako ochronę przed literówkami w literałach, a nie jako pełną walidację.

Template literals z mapped types

Template literal types są najbardziej przydatne w klauzuli as mapped type, gdzie generują nazwy właściwości z innych nazw właściwości:

string & K zostawia tylko klucze typu string, bo Capitalize nie przyjmuje liczb ani symboli. Każdy callback dostaje typ parametru z właściwości, którą obserwuje.

Parsowanie stringów z infer

W typie warunkowym template literal może dopasować string i przechwycić jego części przez infer. Tak wyciąga się nazwy parametrów ze wzorca ścieżki:

Pomiń postId w wywołaniu, a kompilator zgłosi, że go brakuje.

Wyrażenia szablonowe poszerzają się do string

Wyrażenie template string w zwykłym kodzie ma typ string, nawet gdy każda jego część jest typem literału. Dodaj as const, żeby zachować template literal type:

Bez as const przypisanie loose do `log:${Level}` się nie udaje, bo string może być czymkolwiek.

Najczęściej zadawane pytania

Czym są template literal types w TypeScript?

To typy literałów string zapisywane w backtickach z placeholderami ${...}, jak template stringi w JavaScripcie, tylko na poziomie typów. type Greeting = `hello ${string}` przyjmuje każdy string zaczynający się od hello , a `on${Capitalize<"click">}` to typ literału "onClick".

Co się dzieje, gdy wstawisz unię do template literal type?

Szablon jest rozwijany dla każdego elementu, a przy kilku uniach dostajesz każdą kombinację. `${"sm" | "lg"}-${"red" | "blue"}` to "sm-red" | "sm-blue" | "lg-red" | "lg-blue". Bardzo duże kombinacje kończą się błędem TS2590.

Co robią Uppercase, Lowercase, Capitalize i Uncapitalize?

To wbudowane typy, które przekształcają typy literałów string: Uppercase<"id"> to "ID", Lowercase<"ID"> to "id", Capitalize<"name"> to "Name", a Uncapitalize<"Name"> to "name". Zmieniają tylko typy. Żeby zmienić string w czasie wykonania, nadal wywołujesz toUpperCase() i podobne metody.

Czy template literal types sprawdzają stringi w czasie wykonania?

Nie. Jak każdy typ w TypeScript są usuwane przy kompilacji, więc sprawdzają literały string i otypowane wartości tylko w czasie kompilacji. String, który przychodzi w czasie wykonania, z JSON-a albo od użytkownika, jest zwykłym string, dopóki nie sprawdzisz go własnym kodem.

Dlaczego mój template string ma typ string zamiast typu literału?

Wyrażenie szablonowe takie jak `on${event}` jest poszerzane do string przy przypisaniu do zmiennej. Dodaj as const (`on${event}` as const) albo podaj typ docelowy, a TypeScript zachowa template literal type, na przykład "onclick" | "onfocus".

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ