Erro TypeScript: índice de tipo union — solução para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que o TypeScript reclama do seu código?

\n\n

Você já escreveu código em TypeScript que parece absolutamente lógico, mas o compilador de repente exibe um erro assustador? Se você já se deparou com a mensagem «An index signature parameter type cannot be a union type. Consider using a mapped object type instead» — você não está sozinho. Esse erro é uma das perguntas mais populares no Stack Overflow (milhares de visualizações!) e muitas vezes confunde até mesmo desenvolvedores experientes.

\n\n

Neste artigo, não vamos apenas mostrar como corrigir o erro. Vamos entender por que o TypeScript é tão rigoroso e como usar mapped object types para tornar seu código não apenas funcional, mas também mais seguro. Vamos lá!

\n\n

O que é index signature e para que serve?

\n\n

Imagine que você está criando um objeto cujas chaves são strings e os valores são números. Por exemplo, um dicionário com preços de produtos:

\n\n
// Objeto comum\nconst prices = {\n  apple: 100,\n  banana: 50,\n  cherry: 200\n};
\n\n

Mas e se você quiser dizer ao TypeScript: «Olha, este objeto pode ter quaisquer chaves de string, e todos os valores serão números»? Para isso, existe o index signature — uma sintaxe especial que descreve um padrão para todas as propriedades do objeto:

\n\n
// Index signature: [key: string]: number\ninterface PriceMap {\n  [key: string]: number;\n}\n\nconst prices: PriceMap = {\n  apple: 100,\n  banana: 50\n};
\n\n

Aqui, [key: string]: number é o index signature. Ele diz: «Chaves são strings, valores são números». Simples, certo?

\n\n

E qual é o problema com tipos union?

\n\n

Agora imagine que você quer limitar as chaves possíveis a apenas duas opções: 'name' ou 'age'. Parece lógico escrever assim:

\n\n
// ❌ ERRO! Não pode\ninterface Person {\n  [key: 'name' | 'age']: string | number;\n}
\n\n

E então o TypeScript exibe aquele erro: «An index signature parameter type cannot be a union type. Consider using a mapped object type instead».

\n\n

Por quê? Porque o index signature foi feito para descrever um conjunto ilimitado de chaves. Se você quer definir uma lista específica de chaves, isso não é mais um padrão, mas uma descrição exata da estrutura. O TypeScript não permite misturar esses conceitos.

\n\n

Como corrigir o erro? Usando Mapped Object Type

\n\n

A solução que o próprio compilador sugere é usar mapped object type (tipo de objeto mapeado). Parece complicado, mas na prática é apenas uma forma de «percorrer» todas as chaves de um tipo union e criar uma propriedade para cada uma.

\n\n

Veja como fica:

\n\n
// ✅ CORRETO: usando mapped type\ntype Person = {\n  [K in 'name' | 'age']: K extends 'name' ? string : number;\n};\n\n// Ou uma versão mais simples, se os tipos de valores forem iguais:\ntype PersonSimple = {\n  [K in 'name' | 'age']: string | number;\n};
\n\n

Vamos analisar a sintaxe [K in 'name' | 'age']:

\n
    \n
  • K — é uma variável que assume, um por vez, cada valor do tipo union ('name', depois 'age').
  • \n
  • in — palavra-chave que inicia um «loop» sobre os tipos.
  • \n
  • 'name' | 'age' — nosso conjunto de chaves.
  • \n
\n\n

Como resultado, o TypeScript criará um objeto com duas propriedades específicas: name e age. O erro desapareceu!

\n\n

Exemplo com tipos de valores diferentes

\n\n

Muitas vezes, chaves diferentes precisam ter tipos de valores diferentes. Com tipos condicionais (conditional types), isso é resolvido de forma elegante:

\n\n
type Config = {\n  [K in 'host' | 'port' | 'debug']: \n    K extends 'host' ? string :\n    K extends 'port' ? number :\n    boolean;\n};\n\n// Agora:                

Blogs

Book Recommendations