Dicionários em TypeScript: do caos à ordem (guia completo com código)
\n\nImagine que você está escrevendo um aplicativo para aprender inglês. Você precisa armazenar traduções de palavras: "cat" → "gato", "dog" → "cachorro". Qual a melhor forma de organizar esses dados? Claro, usar um dicionário (Dictionary) — uma estrutura de dados onde cada chave é única e está associada a um valor.
Em JavaScript, os dicionários são implementados através de objetos comuns ou Map. Mas o TypeScript adiciona uma tipagem poderosa, transformando coleções caóticas em estruturas rigorosas e previsíveis. Neste artigo, vamos abordar a declaração e inicialização de Dictionary em TypeScript do simples ao complexo. Você aprenderá como evitar erros típicos e escrever código que funciona de forma previsível.
O que é um Dictionary em TypeScript? (E por que não é apenas um objeto)
\n\nEm programação, um Dictionary (dicionário) é uma coleção de pares "chave-valor". Em TypeScript, você pode criá-lo de três maneiras principais:
\n\n- \n
- Objeto com assinatura de índice (
{ [key: string]: T }) \n - Record — tipo utilitário \n
- Map — classe ES6 nativa \n
Cada abordagem tem seus prós e nuances. Vamos analisá-las com exemplos reais.
\n\nMétodo 1: Objeto clássico com assinatura de índice
\n\nA maneira mais popular de declarar um dicionário em TypeScript é usar uma assinatura de índice. Isso diz ao compilador: "O objeto pode ter qualquer número de propriedades com chaves de um tipo específico".
\n\n// Declarando o tipo de dicionário, onde a chave é string, o valor é number\ninterface DictionaryNumber {\n [key: string]: number;\n}\n\n// Inicialização\nconst ages: DictionaryNumber = {\n "Ana": 25,\n "Pedro": 30,\n "Helena": 28\n};\n\n// Adicionando um novo elemento\nages["Olga"] = 35;\n\nconsole.log(ages["Ana"]); // 25\n\nImportante: TypeScript exige que todos os valores correspondam ao tipo declarado. Tentar adicionar uma string causará um erro de compilação:
\n\n// Erro! O tipo 'string' não pode ser atribuído ao tipo 'number'\nages["Olga"] = "trinta e cinco";\n\nQuando usar esta abordagem?
\n- \n
- Quando precisar de um dicionário simples e rápido \n
- Quando as chaves forem strings ou números \n
- Para coleções pequenas (até 1000 elementos) \n
Método 2: Record — sintaxe elegante
\n\nTypeScript fornece o tipo utilitário nativo Record<K, V>. Ele cria um tipo de objeto onde todas as chaves são do tipo K e os valores são do tipo V.
// Declaração e inicialização em uma linha\nconst grades: Record<string, number> = {\n "Matemática": 5,\n "Física": 4,\n "História": 5\n};\n\n// Pode usar enum para as chaves\nenum Subject {\n Math = "math",\n Physics = "physics",\n History = "history"\n}\n\nconst gradesBySubject: Record<Subject, number> = {\n [Subject.Math]: 5,\n [Subject.Physics]: 4,\n [Subject.History]: 5\n};\n\nVantagens do Record:
\n- \n
- Sintaxe concisa \n
- Boa legibilidade \n
- Suporte a tipos union para chaves \n
Método 3: Map — para cenários avançados
\n\nA classe Map do ES6 é uma coleção completa de pares "chave-valor" com recursos adicionais. Em TypeScript, ela é tipada usando genéricos:
// Declaração de Map\nconst userRoles: Map<string, string> = new Map([\n ["admin", "Administrador"],\n ["user", "Usuário"],\n ["guest", "Convidado"]\n]);\n\n// Adicionando\nuserRoles.set("moderator", "Moderador");\n\n// Obtendo\nconsole.log(userRoles.get("admin")); // "Administrador"\n\n// Verificando existência\nif (userRoles.has("user")) {\n console.log("A função existe");\n}\n\n// E