0Pricing
TypeScript Academy · Aula

Recursão no Nível de Tipos

Percorra tipos usando tipos condicionais recursivos.

Recursão no Nível de Tipos é uma aula grátis de TypeScript Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de TypeScript Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de TypeScript Academy inclui 4 aulas no total.

Recursão em tipos

Um tipo condicional pode fazer referência a si mesmo. Isso fornece laços à linguagem de tipos. A maior parte da recursão em nível de tipos percorre uma tupla um elemento por vez, removendo o primeiro elemento e fazendo a recursão sobre o restante.

type Length<T extends unknown[]> =
  T extends [unknown, ...infer Rest]
    ? Length<Rest>
    : 0;
// (this counts down to a base case)

O caso-base

Toda recursão precisa de uma condição de parada. Para tuplas, geralmente é a tupla vazia. Quando o padrão [head, ...rest] deixa de corresponder, você chegou ao fim e retorna um resultado fixo.

type IsEmpty<T extends unknown[]> =
  T extends [] ? true : false;

type A = IsEmpty<[]>;     // true
type B = IsEmpty<[1, 2]>; // false

Primeiro elemento e restante

O movimento central é dividir uma tupla em seu primeiro elemento e na tupla restante, usando infer com o padrão de propagação.

type Head<T extends unknown[]> = T extends [infer H, ...unknown[]] ? H : never;
type Tail<T extends unknown[]> = T extends [unknown, ...infer R] ? R : [];

type A = Head<[1, 2, 3]>; // 1
type B = Tail<[1, 2, 3]>; // [2, 3]

Processamento elemento por elemento

Combine o primeiro elemento, o restante e a recursão para transformar uma tupla inteira. ToStrings reconstrói a tupla, substituindo cada tipo de elemento por string.

type ToStrings<T extends unknown[]> =
  T extends [infer H, ...infer R]
    ? [string, ...ToStrings<R>]
    : [];

type A = ToStrings<[1, true, 3]>; // [string, string, string]

O padrão do acumulador

Muitas vezes, você constrói um resultado em um parâmetro extra chamado acumulador. Ele começa vazio e cresce a cada etapa. Isso evita percorrer a estrutura novamente e é a técnica padrão para laços em nível de tipos.

type Reverse<T extends unknown[], Acc extends unknown[] = []> =
  T extends [infer H, ...infer R]
    ? Reverse<R, [H, ...Acc]>
    : Acc;

type A = Reverse<[1, 2, 3]>; // [3, 2, 1]

Percorrendo o acumulador

Acompanhe Reverse<[1,2,3]>:

  • Etapa 1: H=1, o acumulador passa a ser [1]
  • Etapa 2: H=2, o acumulador passa a ser [2,1]
  • Etapa 3: H=3, o acumulador passa a ser [3,2,1]
  • Tupla vazia; retorne o acumulador = [3,2,1]

O acumulador transporta a resposta a cada chamada recursiva.

type R = Reverse<["a", "b"]>; // ["b", "a"]

Recursão sobre uniões

Você também pode fazer uma recursão para unir cadeias de caracteres. Aqui, concatenamos os elementos de uma tupla em um único tipo literal de cadeia de caracteres, separados por um delimitador.

Notação: o TypeScript real escreve tipos literais de modelo com cadeias delimitadas por acentos graves que contêm lacunas com cifrão e chaves. Nestes trechos, mostramos esse padrão como Tpl<...>, listando cada parte na ordem; por exemplo, um modelo com acento grave que corresponde ao prefixo literal seguido de Rest aparece como Tpl<'prefix', infer Rest>.

type Join<T extends string[], Sep extends string = ','> =
  T extends [infer H extends string, ...infer R extends string[]]
    ? R extends []
      ? H
      : Tpl<H, Sep, Join<R, Sep>>
    : '';
// Tpl<H, Sep, ...> builds a template literal type joining the parts

type A = Join<['a', 'b', 'c']>; // 'a,b,c'

Contagem com recursão

A recursão mais um acumulador podem fazer contagens. Construa uma tupla de unknown com o mesmo comprimento da entrada e, depois, leia sua propriedade length. Você usará muito essa técnica no curso de aritmética.

type Count<T extends unknown[], Acc extends unknown[] = []> =
  T extends [unknown, ...infer R]
    ? Count<R, [unknown, ...Acc]>
    : Acc["length"];

type A = Count<["x", "y", "z"]>; // 3

Filtragem com recursão

Percorra uma tupla e mantenha apenas os elementos que correspondem a uma condição, descartando os demais. Ignore um elemento não o adicionando ao acumulador.

type KeepStrings<T extends unknown[], Acc extends unknown[] = []> =
  T extends [infer H, ...infer R]
    ? H extends string
      ? KeepStrings<R, [...Acc, H]>
      : KeepStrings<R, Acc>
    : Acc;

type A = KeepStrings<[1, "a", 2, "b"]>; // ["a", "b"]

Limites de profundidade da recursão

O compilador limita a profundidade da recursão (historicamente, em torno de 50, embora as otimizações de recursão em cauda permitam mais em alguns padrões). Para tuplas muito grandes, você pode encontrar A instanciação de tipo é excessivamente profunda. Use o estilo com acumulador (em cauda) para elevar esse limite.

type Repeat<T, N extends number, Acc extends T[] = []> =
  Acc["length"] extends N ? Acc : Repeat<T, N, [...Acc, T]>;

type A = Repeat<0, 3>; // [0, 0, 0]

Juntando tudo

A divisão entre primeiro elemento e restante, um caso-base e um acumulador são os três ingredientes de quase todo laço em nível de tipos. Com eles, você pode mapear, filtrar, inverter, contar e unir tuplas inteiramente no sistema de tipos.

type MapToPairs<T extends unknown[], Acc extends unknown[] = []> =
  T extends [infer H, ...infer R]
    ? MapToPairs<R, [...Acc, [H, H]]>
    : Acc;

type A = MapToPairs<[1, 2]>; // [[1, 1], [2, 2]]

Verificação rápida

Teste sua compreensão do padrão do acumulador.

Recapitulação

Agora você já consegue escrever laços em nível de tipos.

  • Condicionais autorreferentes criam recursão.
  • Divida tuplas em [H, ...R] e faça a recursão sobre o restante.
  • Um caso-base (tupla vazia) interrompe o laço.
  • Um acumulador constrói o resultado e permite recursões profundas.

A seguir: como os condicionais se comportam de forma especial sobre uniões.

Perguntas Frequentes

A aula “Recursão no Nível de Tipos” é grátis?

Sim — o texto completo de “Recursão no Nível de Tipos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de TypeScript Academy, atualize para CoddyKit PRO. O curso de TypeScript Academy inclui 4 aulas no total.

O que vou aprender em “Recursão no Nível de Tipos”?

Percorra tipos usando tipos condicionais recursivos. Você pratica TypeScript Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar TypeScript Academy?

Nenhuma experiência prévia é necessária. TypeScript Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Recursão no Nível de Tipos”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de TypeScript Academy?

Sim. Cada aula de TypeScript Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Tipos como Linguagem de Computação
  2. Condicionais no Nível de Tipos
  3. Recursão no Nível de Tipos
  4. Tipos Condicionais Distributivos
← Voltar para TypeScript Academy