Um template literal type monta string literal types com a mesma sintaxe de crases de uma template string do JavaScript. `on${Capitalize<"click" | "focus">}` é o tipo "onClick" | "onFocus", calculado pelo compilador:
Template literal types existem só em tempo de compilação. Eles verificam string literals e valores tipados enquanto você escreve o código; não acrescentam nada ao JavaScript gerado. A tabela de handlers acima usa Record para exigir uma função por nome.
Sintaxe
Dentro das crases você escreve texto literal e placeholders ${...}. Um placeholder guarda um tipo, não um valor: um literal type de string, number, bigint ou boolean, uma union deles, ou um dos tipos amplos string, number, bigint, boolean, null e undefined.
Um placeholder com um tipo amplo como string ou number cria um padrão: o tipo continua sendo `hello ${string}` e qualquer string compatível é aceita. Um placeholder com uma union finita, como boolean, é expandido nos membros dela.
Unions se multiplicam
Com várias unions, o resultado é todas as combinações:
Três tamanhos vezes dois tons dá seis membros. A contagem cresce rápido: cinco placeholders, cada um com uma union de dez letras, dariam 100.000 membros, e o TypeScript recusa com error TS2590: Expression produces a union type that is too complex to represent. Use um placeholder amplo como ${string} quando você não precisar de cada valor exato.
Uppercase, Lowercase, Capitalize, Uncapitalize
Quatro tipos embutidos mudam a caixa de string literal types. Eles são intrínsecos: implementados dentro do compilador, não escritos em TypeScript.
| Tipo | Entrada | Resultado |
|---|---|---|
Uppercase<S> | "hello world" | "HELLO WORLD" |
Lowercase<S> | "Content-Type" | "content-type" |
Capitalize<S> | "hello world" | "Hello world" |
Uncapitalize<S> | "UserName" | "userName" |
Eles só mudam tipos. Para montar a string correspondente em tempo de execução, você ainda chama toUpperCase() ou corta e capitaliza por conta própria, e diz ao TypeScript que o resultado tem o tipo exato:
O as é necessário porque toUpperCase() é tipado para retornar string simples. A assinatura da função é o que quem chama enxerga, então capitalize("report") tem o literal type "Report".
Padrões de string: ${number}px e companhia
Um tipo padrão aceita toda string de um certo formato. Ele é útil para valores CSS, ids e chaves com um prefixo conhecido:
${number} aceita qualquer string que o JavaScript leia como número, o que é mais permissivo do que parece: "-3px", "1e3px" e "0x10px" passam na verificação de tipos. Trate esses padrões como proteção contra erros de digitação em literais, não como validação completa.
Template literals com mapped types
Template literal types são mais úteis como a cláusula as de um mapped type, onde geram nomes de propriedades a partir de outros nomes de propriedades:
string & K mantém só as chaves string, já que Capitalize não aceita números nem symbols. Cada callback recebe o tipo do parâmetro a partir da propriedade que observa.
Analisando strings com infer
Em um conditional type, um template literal pode casar com uma string e capturar partes dela com infer. Isto extrai os nomes dos parâmetros de um padrão de rota:
Deixe postId de fora na chamada e o compilador aponta que ele está faltando.
Expressões de template são ampliadas para string
Uma expressão de template string no código comum tem tipo string, mesmo quando todas as partes são literal types. Adicione as const para manter o template literal type:
Sem as const, atribuir loose a `log:${Level}` falha, porque string pode ser qualquer coisa.
Perguntas frequentes
O que são template literal types no TypeScript?
String literal types escritos com crases e placeholders ${...}, como as template strings do JavaScript, mas no nível dos tipos. type Greeting = `hello ${string}` aceita qualquer string que comece com hello , e `on${Capitalize<"click">}` é o literal type "onClick".
O que acontece quando você coloca uma union em um template literal type?
O template é expandido para cada membro, e com várias unions você recebe todas as combinações. `${"sm" | "lg"}-${"red" | "blue"}` é "sm-red" | "sm-blue" | "lg-red" | "lg-blue". Combinações muito grandes falham com o erro TS2590.
O que Uppercase, Lowercase, Capitalize e Uncapitalize fazem?
São tipos embutidos que transformam string literal types: Uppercase<"id"> é "ID", Lowercase<"ID"> é "id", Capitalize<"name"> é "Name" e Uncapitalize<"Name"> é "name". Eles só mudam tipos; para mudar uma string em tempo de execução você ainda chama toUpperCase() e companhia.
Template literal types validam strings em tempo de execução?
Não. Como todo tipo do TypeScript, eles são apagados, então só verificam string literals e valores tipados em tempo de compilação. Uma string que chega em tempo de execução, vinda de JSON ou de entrada do usuário, é só string até você verificá-la com o seu próprio código.
Por que minha template string tem tipo string em vez de um literal type?
Uma expressão de template como `on${event}` é ampliada para string quando atribuída a uma variável. Adicione as const (`on${event}` as const) ou anote o tipo de destino, e o TypeScript mantém o template literal type, por exemplo "onclick" | "onfocus".