Cómo controlar el tipo de elementos en un objeto indexado de TypeScript

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

¿Por qué este tema explota en Stack Overflow?

\n\n

Si alguna vez has escrito en TypeScript y has intentado crear un objeto donde todos los valores deben ser del mismo tipo, seguramente te has encontrado con este problema. La pregunta "Enforcing the type of the indexed members of a Typescript object" ha acumulado miles de visitas en Stack Overflow no por casualidad: es un "clásico tropiezo" para los desarrolladores que migran desde JavaScript.

\n\n

Imagina: tienes un diccionario de caché, una configuración con claves dinámicas o simplemente un mapa con números. Quieres que TypeScript se asegure de que cada valor en el objeto sea una cadena, un número o algún tipo complejo. Pero el compilador, por alguna razón, deja pasar errores. ¿Te suena familiar?

\n\n

En este artículo, analizaremos todos los enfoques principales para resolver esta tarea: desde simples Index Signatures hasta avanzados Mapped Types. Aprenderás cuándo usar cada método y qué trampas te esperan.

\n\n

El problema: objeto con claves dinámicas

\n\n

Supongamos que estamos escribiendo un sistema de gestión de usuarios. Tenemos un objeto donde las claves son los ID de los usuarios y los valores son sus nombres:

\n\n
interface UserCache {\n  [userId: string]: string;\n}\n\nconst cache: UserCache = {\n  'user_1': 'Alice',\n  'user_2': 'Bob',\n  // 'user_3': 123; // ¡Error! Debe ser una cadena\n};\n\ncache['user_4'] = 'Charlie'; // OK\ncache['user_5'] = 42; // ¡Error! El tipo 'number' no se puede asignar a 'string'\n
\n\n

Parece que funciona. Pero hay un detalle: Index Signature permite cualquier clave de tipo cadena. ¿Y si queremos limitar el conjunto de claves permitidas?

\n\n

Enfoque 1: Index Signature — el clásico

\n\n

Index Signature es la forma más simple de definir el tipo para todos los valores de un objeto. Sintaxis:

\n\n
interface StringMap {\n  [key: string]: string;\n}\n\nconst map: StringMap = {\n  hello: 'world',\n  foo: 'bar',\n};\n
\n\n

Ventajas:

\n
    \n
  • Simplicidad y legibilidad
  • \n
  • Funciona con cualquier cantidad de claves
  • \n
\n\n

Desventajas:

\n
    \n
  • No se puede limitar el conjunto de claves
  • \n
  • Todos los valores deben ser del mismo tipo (o unión)
  • \n
  • No funciona con valores undefined (se necesita precaución)
  • \n
\n\n

Un error común de principiantes: intentar agregar un método a este tipo de objeto:

\n\n
interface BadMap {\n  [key: string]: string;\n  length: number; // ¡Error! 'number' no se puede asignar a 'string'\n}\n
\n\n

Esto no funcionará porque length viola el tipo general. Si necesitas mezclar tipos, usa una unión o Mapped Types.

\n\n

Enfoque 2: Record — un helper incorporado

\n\n

TypeScript proporciona el tipo incorporado Record<K, V>, que hace lo mismo pero con una sintaxis más concisa:

\n\n
type StringRecord = Record<string, string>;\n\nconst config: StringRecord = {\n  apiUrl: 'https://api.example.com',\n  timeout: '5000', // OK, es una cadena\n  // port: 8080, // ¡Error!\n};\n\n// Se pueden limitar las claves:\ntype AllowedKeys = 'name' | 'email' | 'phone';\ntype UserRecord = Record<AllowedKeys, string>;\n\nconst user: UserRecord = {\n  name: 'Alice',\n  email: 'alice@example.com',\n  phone: '+1234567890',\n  // age: '30', // ¡Error! 'age' no está en AllowedKeys\n};\n
\n\n

Cuándo usarlo:

\n
    \n
  • Cuando necesitas crear rápidamente un diccionario tipado
  • \n
  • Cuando las claves son un conjunto específico de valores (unión)
  • \n
  • Para configuraciones con campos conocidos
  • \n
\n\n

Desventaja: Record no permite definir diferentes tipos para diferentes claves. Para eso están los Mapped Types.

\n\n

Enfoque 3: Map — la alternativa de ES6

\n\n

Si usas Map de JavaScript, TypeScript lo tipifica excelentemente

Blogs

Book Recommendations