<h2>Template Literal Types em TypeScript</h2>
<p>Template Literal Types permitem criar tipos baseados em literais de string usando a sintaxe de template literals. Introduzidos no TypeScript 4.4, eles são fundamentais para sistemas de tipos mais expressivos e seguros. Essencialmente, você define um tipo usando a sintaxe ${} dentro de backticks, possibilitando composição dinâmica de tipos.</p>
<p>O caso de uso mais comum é validar e criar tipos para strings com padrões específicos. Imagine um sistema de eventos onde você precisa garantir que event handlers sigam uma convenção de nomenclatura:</p>
<pre><code class="language-typescript">type EventType = "click" | "hover" | "focus";
type EventHandler = on${Capitalize<EventType>};
// Resultado: "onClick" | "onHover" | "onFocus"
const handler: EventHandler = "onClick"; // ✓ válido
const invalid: EventHandler = "onchange"; // ✗ erro</code></pre>
<h3>Combinando Union Types</h3>
<p>Template Literal Types brilham ao combinar múltiplas unions, criando todas as combinações possíveis:</p>
<pre><code class="language-typescript">type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE"; type Endpoint = "users" | "posts" | "comments";
type APIRoute = /${HTTPMethod}/${Endpoint};
// Gera 12 combinações automaticamente
const route1: APIRoute = "/GET/users"; // ✓
const route2: APIRoute = "/POST/posts"; // ✓
const route3: APIRoute = "/PATCH/users"; // ✗ erro</code></pre>
<h3>Type Inference e Extração</h3>
<p>Você pode extrair partes de uma string usando <code>infer</code> em tipos condicionais:</p>
<pre><code class="language-typescript">type ExtractMethod<T> =
T extends /${infer M}/${infer E} ? M : never;
type Method = ExtractMethod<"/GET/users">; // "GET"</code></pre>
<h2>Recursive Types: Estruturando Dados Infinitos</h2>
<p>Recursive Types permitem que um tipo se referencie, essencial para estruturas de árvore, grafos ou padrões aninhados. Ao contrário da recursão infinita, o TypeScript "expande" o tipo apenas quando necessário, mantendo performance.</p>
<p>A aplicação clássica é criar tipos para estruturas aninhadas arbitrárias. Considere um sistema de validação de objetos profundamente aninhados:</p>
<pre><code class="language-typescript">type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
interface User {
name: string;
profile: {
bio: string;
settings: {
notifications: boolean;
}
}
}
const partial: DeepPartial<User> = {
profile: {
settings: {} // válido: qualquer nível pode ser omitido
}
};</code></pre>
<h3>Recursive Types para Estruturas Heterogêneas</h3>
<p>Sistemas que processam JSONs complexos se beneficiam enormemente. Veja uma implementação de tipo para qualquer JSON válido:</p>
<pre><code class="language-typescript">type JSON =
string | number | boolean | null | JSON[] | { [key: string]: JSON };
const validJSON: JSON = {
user: {
name: "Ana",
scores: [10, 20, { nested: true }],
active: null
}
}; // ✓ totalmente type-safe</code></pre>
<h3>Limiting Recursion com Profundidade Máxima</h3>
<p>Para evitar problemas de performance em certos cenários, você pode limitar a profundidade de recursão:</p>
<pre><code class="language-typescript">type DeepReadonly<T, Depth extends number = 5> =
Depth extends 0
? T
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K], [-1, 0, 1, 2, 3, 4][Depth]> }
: T;</code></pre>
<h2>Combinando Template Literals com Tipos Recursivos</h2>
<p>A fusão de ambas as técnicas cria sistemas de tipos incrivelmente poderosos. Um exemplo prático: validar objetos com chaves dinâmicas baseadas em um padrão:</p>
<pre><code class="language-typescript">type DeepKeys<T, Prefix = ""> = T extends object
? {
[K in keyof T]: K extends string
? ${Prefix}${K} | DeepKeys<T[K], ${Prefix}${K}.>
: never
}[keyof T]
: never;
interface Config {
database: {
host: string;
port: number;
credentials: {
username: string;
password: string;
}
}
cache: {
enabled: boolean;
}
}
type ConfigPaths = DeepKeys<Config>;
// "database" | "database.host" | "database.port" // "database.credentials" | "database.credentials.username" | ...
function getConfig(key: ConfigPaths): string | number | boolean {
// implementação segura
return "";
}
getConfig("database.credentials.username"); // ✓
getConfig("database.invalid"); // ✗ erro em tempo de compilação</code></pre>
<p>Esse padrão é usado em bibliotecas como Zod, tRPC e frameworks modernos para garantir type-safety em configurações complexas. A recursão navega por cada nível do objeto, enquanto template literals constroem strings do caminho dinamicamente.</p>
<h2>Conclusão</h2>
<p>Template Literal Types e Recursive Types são ferramentas avançadas que transformam o TypeScript de uma camada de validação em um <strong>poderoso sistema de constraints em tempo de compilação</strong>. Template Literals permitem criar tipos baseados em padrões de string com composição elegante, enquanto Recursive Types resolvem o desafio de representar estruturas aninhadas de profundidade arbitrária.</p>
<p>Dominar essas técnicas eleva significativamente a qualidade do seu código: erros são capturados antes de executar, autocompletar fica mais inteligente, e refatorações ficam seguras. Comece praticando com casos simples (validação de rotas, chaves de configuração) e evolua gradualmente para sistemas mais complexos.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook: Template Literal Types</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook: Conditional Types</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html" target="_blank" rel="noopener noreferrer">Advanced TypeScript: Recursive Types</a></li>
<li><a href="https://www.totaltypescript.com/" target="_blank" rel="noopener noreferrer">Total TypeScript: Advanced Type Patterns</a></li>
<li><a href="https://www.oreilly.com/library/view/programming-typescript/9781492037644/" target="_blank" rel="noopener noreferrer">Programming TypeScript - Boris Cherny (O'Reilly Media)</a></li>
</ul>