Arrays de objetos en TypeScript: tutorial paso a paso para quienes están hartos de los errores
\n\n¿Alguna vez has escrito en TypeScript y de repente has recibido un subrayado rojo del IDE al intentar añadir un objeto a un array? Te suena, ¿verdad? La pregunta "How can I define an array of objects?" es una de las más populares en Stack Overflow. Y no es para menos: sin una tipificación correcta de los arrays de objetos, tu código se convierte en una fuente de bugs y dolores de cabeza.
\n\nEn este tutorial analizaremos todas las formas de definir un array de objetos en TypeScript, desde las más simples hasta las más avanzadas. Aprenderás a evitar errores comunes, a usar interfaces y a hacer que tu código no solo funcione, sino que también sea elegante. ¡Allá vamos!
\n\n¿Por qué simplemente [] no funciona?
\n\nSupongamos que escribes:
\n\nlet users = [];\n\nTypeScript lo interpreta como never[] — un array que nunca debería contener elementos. Intenta añadirle un objeto:
users.push({ name: 'Ana', age: 25 }); // ¡Error!\n\nEl IDE gritará: "Argument of type '{ name: string; age: number; }' is not assignable to parameter of type 'never'." TypeScript no sabe qué vas a almacenar en el array, por lo que bloquea cualquier inserción.
\n\nLa solución es indicar explícitamente el tipo del array. Analicemos todas las opciones.
\n\nForma 1: Anotación de tipo básica — corchetes
\n\nLa forma más sencilla e intuitiva es usar la sintaxis Tipo[]:
let users: { name: string; age: number }[] = [];\n\nusers.push({ name: 'Ana', age: 25 }); // ✅ Funciona\nusers.push({ name: 'Iván', age: 30 }); // ✅ Funciona\n\n\nAquí le decimos a TypeScript: "Oye, esto es un array de objetos, cada uno de los cuales tiene las propiedades name (cadena) y age (número)". Ahora el IDE está contento, el autocompletado funciona y los errores de tipo se detectan en tiempo de compilación.
\n\nInconveniente: si la estructura del objeto es compleja, describirla directamente en la anotación se vuelve engorroso. Para estos casos se inventaron las interfaces.
\n\nForma 2: Interfaces — tu mejor amiga
\n\nLas interfaces permiten extraer la descripción del objeto a una entidad separada y reutilizarla. Esto hace que el código sea más limpio y comprensible:
\n\ninterface User {\n id: number;\n name: string;\n age: number;\n email?: string; // propiedad opcional\n}\n\nlet users: User[] = [];\n\nusers.push({ id: 1, name: 'Ana', age: 25 });\nusers.push({ id: 2, name: 'Iván', age: 30, email: 'ivan@example.com' }); // ✅\n\n\nAhora, si intentas añadir un objeto sin el campo id o con un tipo incorrecto, TypeScript mostrará un error. Las interfaces son especialmente útiles cuando el mismo tipo de objeto se utiliza en varios lugares.
¿Y qué hay de type?
\n\nEn lugar de interface se puede usar type:
type User = {\n id: number;\n name: string;\n age: number;\n};\n\nlet users: User[] = [];\n\nLa diferencia entre interface y type es tema para otro artículo. Para arrays de objetos se pueden usar ambas opciones, pero interface se aplica con más frecuencia para describir formas de objetos.
Forma 3: Sintaxis genérica Array<Type>
\n\nUna forma alternativa es usar genéricos:
\n\nlet users: Array<{ name: string; age: number }> = [];\n\n// O con una interfaz:\nlet users: Array<User> = [];\n\n\nAmbas sintaxis (Type[] y Array<Type>) funcionan igual. La elección es cuestión de gusto y contexto. Personalmente prefiero Type[] para tipos simples y Array<Type> para construcciones genéricas complejas. Pero lo importante es ser coherente en el proyecto.
Forma 4: Creación de un array con objetos iniciales
\n\nA menudo no solo hay que declarar el array, sino también llenarlo inmediatamente con datos. TypeScr