¿Cómo asignar propiedades dinámicamente a un objeto en TypeScript? Explicación clara para principiantes
\n\n¡Hola, amigo! Si alguna vez has escrito en JavaScript y luego has pasado a TypeScript, seguramente te has encontrado con la situación de necesitar agregar una nueva propiedad a un objeto sobre la marcha. En JS se hace en un santiamén: obj.newProp = 'value'. Pero cuando intentas lo mismo en TypeScript, el compilador empieza a quejarse: "Property 'newProp' does not exist on type ...". ¿Te suena?
No te preocupes, es normal. TypeScript nos protege de errores accidentales, pero a veces su rigurosidad parece excesiva. En este artículo, analizaremos cómo asignar propiedades dinámicamente a objetos de forma correcta y segura. Aprenderás varios métodos probados, desde los más simples hasta los más elegantes. ¡Allá vamos!
\n\n¿Por qué se queja TypeScript?
\n\nAntes de resolver el problema, entendamos su raíz. TypeScript es una extensión de JavaScript que añade tipado estático. Cuando declaras un objeto:
\n\nconst user = { name: 'Ana', age: 25 };\n\n\nTypeScript infiere automáticamente su tipo: { name: string; age: number }. Esto significa que el objeto user solo puede contener esas dos propiedades. Intentar agregar email provocará un error de compilación:
user.email = 'anna@example.com'; // ❌ ¡Error!\n\n\nTypeScript no sabe que esa propiedad puede aparecer y bloquea el código. Pero en la vida real, a menudo es necesario agregar propiedades dinámicamente, por ejemplo, al trabajar con datos de una API o formularios. Veamos cómo hacerlo correctamente.
\n\nMétodo 1: El más simple — as any
\n\nUna forma rápida pero poco limpia es usar as any. Literalmente le dice a TypeScript: "Desactiva la verificación de tipos para este objeto".
const user: any = { name: 'Ana', age: 25 };\nuser.email = 'anna@example.com'; // ✅ Funciona\nuser.isAdmin = true; // ✅ Funciona\n\n\n¿Por qué es malo? Porque pierdes todas las ventajas de TypeScript: autocompletado, verificación de tipos, protección contra errores tipográficos. Si accidentalmente escribes user.emial, no habrá error; te darás cuenta solo en tiempo de ejecución. Usa este método solo para prototipado rápido o cuando sepas exactamente lo que haces.
Método 2: Firma de índice (Index Signature)
\n\nUn enfoque más correcto es declarar de antemano que el objeto puede contener propiedades dinámicas. Para ello se utiliza la firma de índice.
\n\ninterface User {\n name: string;\n age: number;\n [key: string]: any; // 👈 Permitimos cualquier propiedad adicional\n}\n\nconst user: User = { name: 'Ana', age: 25 };\nuser.email = 'anna@example.com'; // ✅ Funciona\nuser.phone = '+7-999-123-45-67'; // ✅ Funciona\n\n\n¿Qué sucede aquí? La notación [key: string]: any significa: "el objeto puede tener cualquier clave de tipo string, y sus valores pueden ser de cualquier tipo". Ahora puedes agregar propiedades dinámicamente y TypeScript no se quejará.
Detalle importante: si quieres limitar los tipos de valores, reemplaza any por un tipo específico:
interface User {\n name: string;\n age: number;\n [key: string]: string | number; // Solo strings y números\n}\n\n\nLa firma de índice es una excelente opción cuando sabes de antemano que el objeto se expandirá. Pero ten cuidado: si la interfaz tiene otras propiedades con otros tipos, también deben coincidir con la firma.
\n\nMétodo 3: Tipo utilitario Record
\n\nSi necesitas crear un objeto donde todas las claves y valores sean del mismo tipo, usa el tipo incorporado Record<Keys, Type>. Es ideal para diccionarios o mapeos.
type UserRoles = Record<string, 'admin' | 'user' | 'guest'>;\n\nconst roles: UserRoles = {\n ana: 'admin',\n ivan: 'user',\n};\