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.
| Typ | Wejście | Wynik |
|---|---|---|
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".