Template Literal Types no TypeScript 2026
Domine template literal types no TypeScript. Crie tipos string dinâmicos, padrões de evento e chaves geradas automaticamente com exemplos do mundo real.
O Que São Template Literal Types
Template literal types usam a mesma sintaxe de template strings do JavaScript, mas no nível dos tipos. Em vez de montar strings em runtime, você monta tipos de string em tempo de compilação. A sintaxe é `${Type}` dentro de um tipo.
Quando você escreve type Saudacao = `Olá, ${string}`, o TypeScript aceita qualquer string que comece com 'Olá, '. Se escrever `${"get" | "set"}${string}`, aceita qualquer string que comece com get ou set. O compilador verifica isso antes do código executar.
A mágica aparece quando você combina template literals com union types. Se você tem type Cor = 'red' | 'blue' e type Tamanho = 'sm' | 'lg', o tipo `${Cor}-${Tamanho}` gera automaticamente 'red-sm' | 'red-lg' | 'blue-sm' | 'blue-lg'. O TypeScript faz o produto cartesiano sozinho.
O TypeScript ainda traz 4 utility types de manipulação de string: Uppercase, Lowercase, Capitalize e Uncapitalize. Eles transformam tipos string literais. Uppercase<'hello'> vira 'HELLO'. Isso abre portas pra gerar nomes de eventos, getters, setters e rotas de forma automática.
Como Usar Template Literal Types Passo a Passo
Vamos construir do mais simples ao mais sofisticado. Cada passo desbloqueia um padrão novo.
Exemplos Práticos de Template Literal Types
Hora de ver código. Cada exemplo resolve um problema concreto de tipagem.
Tipos String Básicos com Template
// Template literal type básico
type ApiRoute = `/api/${string}`;
const rota1: ApiRoute = "/api/users"; // OK
const rota2: ApiRoute = "/api/posts/123"; // OK
// const rota3: ApiRoute = "/users"; // Error!
// Combinando unions: produto cartesiano automático
type Cor = "red" | "green" | "blue";
type Tamanho = "sm" | "md" | "lg";
type ClasseCSS = `${Cor}-${Tamanho}`;
// Resultado: "red-sm" | "red-md" | "red-lg" |
// "green-sm" | "green-md" | "green-lg" |
// "blue-sm" | "blue-md" | "blue-lg"
const classe: ClasseCSS = "red-lg"; // OK
// const errada: ClasseCSS = "red-xl"; // Error!
Utility Types de Manipulação de String
// Uppercase: tudo maiúsculo
type A = Uppercase<"hello">; // "HELLO"
type B = Uppercase<"world">; // "WORLD"
// Lowercase: tudo minúsculo
type C = Lowercase<"HELLO">; // "hello"
// Capitalize: primeira letra maiúscula
type D = Capitalize<"name">; // "Name"
type E = Capitalize<"email">; // "Email"
// Uncapitalize: primeira letra minúscula
type F = Uncapitalize<"Name">; // "name"
// Combinando com template literals
type Campo = "name" | "email" | "age";
type Getter = `get${Capitalize<Campo>}`;
// "getName" | "getEmail" | "getAge"
type Setter = `set${Capitalize<Campo>}`;
// "setName" | "setEmail" | "setAge"
type EnvVar = `APP_${Uppercase<Campo>}`;
// "APP_NAME" | "APP_EMAIL" | "APP_AGE"
Padrões de Eventos Tipados
// Gerando nomes de handler a partir de campos
type FormField = "name" | "email" | "password";
type OnChange = `on${Capitalize<FormField>}Change`;
// "onNameChange" | "onEmailChange" | "onPasswordChange"
type OnBlur = `on${Capitalize<FormField>}Blur`;
// "onNameBlur" | "onEmailBlur" | "onPasswordBlur"
// Tipando um sistema de eventos completo
type EventName = "click" | "hover" | "focus" | "blur";
type ElementId = "submit-btn" | "cancel-btn" | "search-input";
type EventKey = `${ElementId}:${EventName}`;
// "submit-btn:click" | "submit-btn:hover" | ... (16 combinações)
const handlers: Record<EventKey, () => void> = {
"submit-btn:click": () => console.log("submit"),
"submit-btn:hover": () => console.log("hover"),
// ... TypeScript exige todas as 16 chaves
};
Gerando Tipos de Objeto com Chaves Dinâmicas
// Gerando getters e setters tipados
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type Setters<T> = {
[K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};
interface User {
name: string;
age: number;
active: boolean;
}
type UserGetters = Getters<User>;
// {
// getName: () => string;
// getAge: () => number;
// getActive: () => boolean;
// }
type UserSetters = Setters<User>;
// {
// setName: (value: string) => void;
// setAge: (value: number) => void;
// setActive: (value: boolean) => void;
// }
// Combinando tudo
type UserAccessors = Getters<User> & Setters<User>;
Rotas de API Tipadas
// Tipando rotas REST
type Recurso = "users" | "posts" | "comments";
type Metodo = "GET" | "POST" | "PUT" | "DELETE";
type RotaBase = `/api/v1/${Recurso}`;
// "/api/v1/users" | "/api/v1/posts" | "/api/v1/comments"
type RotaComId = `/api/v1/${Recurso}/${number}`;
// "/api/v1/users/${number}" | ...
// Extraindo partes de uma rota com infer
type ExtrairRecurso<T> = T extends `/api/v1/${infer R}/${number}`
? R
: T extends `/api/v1/${infer R}`
? R
: never;
type R1 = ExtrairRecurso<"/api/v1/users">; // "users"
type R2 = ExtrairRecurso<"/api/v1/posts/42">; // "posts"
Percebe o poder? Você define as partes (recursos, métodos, campos) e o TypeScript gera todas as combinações válidas. Typos viram erros de compilação. Rotas inexistentes não passam no type check. É autocomplete completo sem runtime overhead.
Erros Comuns com Template Literal Types
Armadilhas que travam sua tipagem de strings
Explosão combinatória: se você combina duas unions de 10 elementos cada, o TypeScript gera 100 tipos. Três unions de 10 geram 1000. O compilador fica lento. Mantenha as unions pequenas ou use string com validação runtime.
Confundir tipo com valor: `${"get"}Name` é um tipo literal, não uma string JavaScript. Não dá pra usar template literal types pra gerar strings em runtime. Eles existem só no sistema de tipos.
Esquecer o string & K em mapped types: quando usa K in keyof T dentro de um template, o K pode ser string | number | symbol. Faça string & K pra garantir que só strings entrem no template.
Capitalize não funciona com variáveis: Capitalize<T> funciona com tipos literais ('hello' vira 'Hello'). Se T for string genérico, o resultado é string. Precisa de tipos literais concretos pra manipulação funcionar.
Não usar as const em objetos: se você quer que o TypeScript infira tipos literais das strings de um objeto, use as const na declaração. Sem isso, as strings viram string genérico e o template literal perde a precisão.
Checklist de Template Literal Types
TypeScript Avançado na Prática
Template literal types são a cola que conecta strings dinâmicas ao sistema de tipos estático. Mas num projeto de produção, eles brilham quando combinados com mapped types, infer e generics pra criar APIs internas que se documentam sozinhas. No CrazyStack, você usa essas técnicas pra construir um SaaS completo com Node.js, React e TypeScript.
Se você quer criar abstrações que geram tipos automaticamente e fazem o compilador trabalhar a seu favor, esse é o caminho certo.
Continue lendo
Como Usar Mapped Types no TypeScript
Transforme tipos existentes criando novos tipos com mapped types.
Como Usar Infer no TypeScript
Extraia tipos automaticamente com a keyword infer dentro de conditional types.
Como Usar Conditional Types no TypeScript
Domine tipos condicionais e crie lógica de tipos no nível do compilador.
Interface no TypeScript
Quando usar interface