Introdução: quando o TypeScript diz «não» a uma simples string
\n\nVocê está programando em TypeScript, tudo vai bem, mas de repente o compilador emite uma mensagem assustadora:
\n\nElement implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ ... }'.\n\nSituação familiar? Se você já trabalhou com objetos e chaves dinâmicas em TypeScript, quase certamente já encontrou esse erro. Ele está entre os 5 erros mais frequentes no Stack Overflow sobre TypeScript, e não é à toa.
\n\nNeste artigo, vamos analisar por que esse erro ocorre, como corrigi-lo corretamente e — o mais importante — como projetar o código para que ele nunca apareça. O artigo será útil tanto para iniciantes que estão aprendendo TypeScript quanto para desenvolvedores experientes que desejam revisar o assunto.
\n\nO que significa esse erro? Explicação simples
\n\nTypeScript é uma linguagem de tipagem estrita. Ele garante que você não acesse propriedades de um objeto com um tipo de chave incorreto. Vamos imaginar uma situação simples:
\n\nconst user = {\n name: 'Ana',\n age: 25,\n city: 'Moscou'\n};\n\nconst key: string = 'name';\nconsole.log(user[key]); // ❌ Erro!\n\nÀ primeira vista, tudo parece lógico: o objeto user tem a propriedade name, e passamos a string 'name'. Mas o TypeScript vê um problema: o tipo da variável key é string, e não um literal específico 'name' | 'age' | 'city'.
Imagine que você vai a uma biblioteca e diz: «Me dê um livro». O bibliotecário perguntará: «Qual exatamente?» — afinal, existem milhares de livros. O TypeScript funciona da mesma forma: ele não pode garantir que qualquer string corresponda a uma propriedade do objeto.
\n\nO erro traduzido literalmente é: «O elemento tem implicitamente o tipo any, porque a expressão do tipo string não pode ser usada para indexar». Em palavras simples: você está tentando acessar um objeto com uma chave cujo tipo é muito genérico.
\n\nTop 5 situações em que o erro ocorre
\n\n1. Acesso dinâmico a propriedades de objeto
\n\nO caso mais comum é quando você obtém uma chave de uma fonte externa (API, entrada do usuário, array de chaves):
\n\nconst config = {\n theme: 'dark',\n language: 'ru',\n notifications: true\n};\n\nfunction getConfigValue(key: string) {\n return config[key]; // ❌ Erro!\n}\n\n2. Trabalhando com enum ou constantes
\n\nconst COLORS = {\n red: '#FF0000',\n green: '#00FF00',\n blue: '#0000FF'\n};\n\nfunction getColorCode(colorName: string) {\n return COLORS[colorName]; // ❌ Erro!\n}\n\n3. Iteração sobre chaves de objeto com Object.keys()
\n\nconst scores = {\n math: 95,\n physics: 88,\n chemistry: 92\n};\n\nObject.keys(scores).forEach(key => {\n console.log(scores[key]); // ❌ Erro!\n});\n\nEsta é uma «armadilha» clássica: Object.keys() retorna string[], e não (keyof typeof scores)[].
4. Uso de Map ou Record com genéricos
\n\nconst cache: Record<string, any> = {};\nconst key: string = 'user_123';\ncache[key] = { name: 'Ivan' }; // ✅ Funciona\n\n// Mas se tiparmos com mais precisão:\ninterface UserCache {\n [id: string]: { name: string };\n}\nconst users: UserCache = {};\nconst userId: string = 'user_456';\nconsole.log(users[userId]); // ❌ Erro!\n\n5. Funções que recebem chaves como parâmetros
\n\ninterface Product {\n id: number;\n title: string;\n price: number;\n}\n\nfunction updateProductField(product: Product, field: string, value: any) {\n product[field] = value; // ❌ Erro!\n}\n\n5 formas de corrigir o erro (da simples à correta)
\n\nForma 1: Type assertion (as any) — rápido, mas perigoso
\n\nA maneira mais simples e mais «suja»