Infer no TypeScript: Extrair Tipos 2026
Domine a keyword infer no TypeScript. Aprenda a extrair tipos automaticamente dentro de conditional types com exemplos que você aplica direto no projeto.
O Que É Infer no TypeScript
Infer é uma keyword que só funciona dentro de conditional types. Ela serve pra capturar um tipo que o compilador já conhece, mas que você quer extrair e usar separadamente. Pensa nela como uma variável temporária dentro de uma expressão de tipo.
Quando você escreve T extends SomeType<infer U> ? U : never, o TypeScript tenta encaixar T no formato de SomeType. Se conseguir, ele captura o tipo interno em U e retorna. Se não conseguir, cai no never. Simples assim.
A sacada é que infer faz pattern matching no nível dos tipos. Ela olha pra estrutura de um tipo e puxa a parte que você quer. Funciona com funções, arrays, Promises, objetos, tuplas e qualquer estrutura que o TypeScript consiga desmontar.
Galera confunde infer com generics, mas são coisas diferentes. Generics você passa explicitamente: Array<string>. Com infer, o compilador descobre sozinho qual tipo tá ali dentro. Você não passa nada. Ele extrai.
Como Usar Infer Passo a Passo
Vamos construir do zero. Cada passo adiciona uma camada de entendimento sobre como infer funciona na prática.
Exemplos Práticos com Infer
Código na tela vale mais que teoria. Veja cada padrão de infer aplicado em cenários reais.
Extraindo Tipo de Retorno de Funções
// Criando nosso próprio ReturnType
type ReturnOf<T> = T extends (...args: any[]) => infer R ? R : never;
// Testando com funções reais
function getUser() {
return { id: 1, name: "Maria", active: true };
}
type User = ReturnOf<typeof getUser>;
// Resultado: { id: number; name: string; active: boolean }
function calcularPreco(base: number, desconto: number) {
return base - (base * desconto);
}
type Preco = ReturnOf<typeof calcularPreco>;
// Resultado: number
Extraindo Elementos de Array e Tupla
// Tipo de elemento de um array
type ElementOf<T> = T extends (infer E)[] ? E : never;
type A = ElementOf<string[]>; // string
type B = ElementOf<number[]>; // number
type C = ElementOf<(string | number)[]>; // string | number
// Extrair primeiro e último de tupla
type First<T> = T extends [infer F, ...any[]] ? F : never;
type Last<T> = T extends [...any[], infer L] ? L : never;
type Tupla = [string, number, boolean];
type Primeiro = First<Tupla>; // string
type Ultimo = Last<Tupla>; // boolean
Unwrap de Promise e Tipos Aninhados
// Unwrap simples de Promise
type UnwrapPromise<T> = T extends Promise<infer V> ? V : T;
type R1 = UnwrapPromise<Promise<string>>; // string
type R2 = UnwrapPromise<Promise<number>>; // number
type R3 = UnwrapPromise<string>; // string (não é Promise)
// Unwrap profundo (Promise de Promise)
type DeepUnwrap<T> = T extends Promise<infer V>
? DeepUnwrap<V>
: T;
type D1 = DeepUnwrap<Promise<Promise<string>>>; // string
type D2 = DeepUnwrap<Promise<Promise<Promise<number>>>>; // number
// Extrair retorno de função async
type AsyncReturn<T> = T extends (...args: any[]) => Promise<infer R>
? R
: never;
async function fetchUsers() {
return [{ id: 1, name: "João" }];
}
type Users = AsyncReturn<typeof fetchUsers>;
// { id: number; name: string }[]
Padrões Avançados com Múltiplos Infer
// Extrair partes de uma função
type FuncParts<T> = T extends (arg: infer A) => infer R
? { input: A; output: R }
: never;
function converter(valor: string): number {
return Number(valor);
}
type Partes = FuncParts<typeof converter>;
// { input: string; output: number }
// Extrair tipo de propriedade específica
type PropType<T, K extends keyof T> = T extends { [P in K]: infer V }
? V
: never;
interface Config {
host: string;
port: number;
debug: boolean;
}
type HostType = PropType<Config, "host">; // string
type PortType = PropType<Config, "port">; // number
// Extrair tipo de evento de um EventEmitter
type EventPayload<T> = T extends (event: string, payload: infer P) => void
? P
: never;
type Handler = (event: string, payload: { userId: number }) => void;
type Payload = EventPayload<Handler>; // { userId: number }
Cada um desses padrões resolve um problema concreto. O ReturnOf elimina a necessidade de criar tipos manuais pra cada função. O UnwrapPromise limpa código assíncrono. O FuncParts monta abstrações que se adaptam sozinhas. É o tipo de ferramenta que, depois que você aprende, não dá mais pra voltar atrás.
Erros Comuns com Infer
Armadilhas que travam seu código de tipos
Usar infer fora de conditional types: infer só funciona dentro de T extends ... ? ... : .... Se você tentar usar em qualquer outro lugar, o compilador vai gritar. Não tem exceção.
Esquecer o fallback com never: quando o tipo não bate com o pattern, o resultado precisa ser algo. Use never pra indicar que aquele caso é impossível. Se usar any, você perde a segurança.
Criar recursão infinita: DeepUnwrap funciona, mas se você não tiver o caso base (quando T não é Promise, retorna T), o compilador entra em loop. Sempre tenha uma saída.
Confundir posição do infer: em T extends (infer A) => infer R, o A captura o parâmetro e o R captura o retorno. Se você inverter, o tipo vai sair errado e o erro não vai ser óbvio.
Não testar com tipos literais: infer pode se comportar diferente com string vs 'hello'. Teste seus utility types com tipos literais, unions e never pra garantir que funcionam em todos os cenários.
Checklist de Uso do Infer
TypeScript Avançado na Prática
Infer é uma das ferramentas mais poderosas do sistema de tipos do TypeScript. Mas ela brilha de verdade quando combinada com generics, mapped types e template literal types num projeto real. No CrazyStack, você usa tudo isso pra construir um SaaS completo com Node.js, React e TypeScript do zero ao deploy.
Se você quer sair do nível 'sabe tipar variável' pro nível 'cria utility types que o time inteiro usa', esse é o caminho.
Continue lendo
Como Criar Type Guard no TypeScript
A criar type guards customizados com a keyword is e narrowing de tipos.
Como Usar Conditional Types no TypeScript
Domine tipos condicionais e crie lógica de tipos no nível do compilador.
Como Usar Utility Types no TypeScript
Partial, Required, Pick, Omit e todos os utility types nativos do TypeScript.
Interface no TypeScript
Quando usar interface