Error de TypeScript: índice de tipo unión — solución para principiantes

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué TypeScript se queja de tu código?

\n\n

¿Alguna vez has escrito código en TypeScript que parece absolutamente lógico, pero el compilador de repente muestra un error aterrador? Si te has encontrado con el mensaje «An index signature parameter type cannot be a union type. Consider using a mapped object type instead» — no estás solo. Este error es una de las preguntas más populares en Stack Overflow (¡miles de visitas!) y a menudo desconcierta incluso a desarrolladores experimentados.

\n\n

En este artículo no solo mostraremos cómo corregir el error. Analizaremos por qué TypeScript es tan estricto y cómo usar mapped object types para que tu código no solo funcione, sino que también sea más seguro. ¡Allá vamos!

\n\n

¿Qué es un index signature y para qué sirve?

\n\n

Imagina que creas un objeto cuyas claves son cadenas y los valores son números. Por ejemplo, un diccionario con precios de productos:

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

Pero, ¿qué pasa si quieres decirle a TypeScript: «Oye, este objeto puede tener cualquier clave de tipo cadena, y todos los valores serán números»? Para eso sirve el index signature — una sintaxis especial que describe una plantilla para todas las propiedades del 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

Aquí [key: string]: number es el index signature. Dice: «Las claves son cadenas, los valores son números». Sencillo, ¿verdad?

\n\n

¿Y cuál es el problema con los tipos unión?

\n\n

Ahora imagina que quieres limitar las claves posibles solo a dos opciones: 'name' o 'age'. Parece lógico escribir así:

\n\n
// ❌ ¡ERROR! No se puede así\ninterface Person {\n  [key: 'name' | 'age']: string | number;\n}
\n\n

Y aquí TypeScript muestra el error mencionado: «An index signature parameter type cannot be a union type. Consider using a mapped object type instead».

\n\n

¿Por qué? Porque el index signature está diseñado para describir un conjunto ilimitado de claves. Si quieres definir una lista específica de claves, ya no es una plantilla, sino una descripción precisa de la estructura. TypeScript no permite mezclar estos conceptos.

\n\n

¿Cómo corregir el error? Usando Mapped Object Type

\n\n

La solución que sugiere el propio compilador es usar un mapped object type (tipo de objeto mapeado). Suena complicado, pero en realidad es solo una forma de «recorrer» todas las claves de un tipo unión y crear una propiedad para cada una.

\n\n

Así es como se ve:

\n\n
// ✅ CORRECTO: usando mapped type\ntype Person = {\n  [K in 'name' | 'age']: K extends 'name' ? string : number;\n};\n\n// O una versión más simple, si los tipos de valores son iguales:\ntype PersonSimple = {\n  [K in 'name' | 'age']: string | number;\n};
\n\n

Analicemos la sintaxis [K in 'name' | 'age']:

\n
    \n
  • K — es una variable que toma, uno por uno, cada valor del tipo unión ('name', luego 'age').
  • \n
  • in — palabra clave que inicia un «bucle» sobre los tipos.
  • \n
  • 'name' | 'age' — nuestro conjunto de claves.
  • \n
\n\n

Como resultado, TypeScript creará un objeto con dos propiedades específicas: name y age. ¡El error ha desaparecido!

\n\n

Ejemplo con diferentes tipos de valores

\n\n

A menudo sucede que diferentes claves deben tener diferentes tipos de valores. Con tipos condicionales (conditional types) esto se resuelve de manera 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// Ahora:                

Blogs

Book Recommendations