Introducción: ¿por qué TypeScript se queja de un array vacío?
\n\n¿Alguna vez ha escrito código en TypeScript, ha ejecutado la compilación y ha recibido un mensaje misterioso: "Argument of type 'X' is not assignable to parameter of type 'never'"? Si es así, no está solo. Este error es un verdadero obstáculo para desarrolladores de todos los niveles. En Stack Overflow, esta pregunta ha acumulado miles de visitas, y hoy la analizaremos de una vez por todas.
Imagine la situación: declara un array vacío, intenta agregarle algo y TypeScript bloquea la operación. ¿Le suena familiar? Averigüemos por qué sucede esto y, lo más importante, cómo solucionarlo.
\n\nEn este artículo no solo traduciremos documentación técnica. Recorreremos el camino desde la aparición del error hasta su eliminación completa con ejemplos reales que podrá aplicar de inmediato en sus proyectos.
\n\n¿Qué es el tipo never en TypeScript?
\n\nAntes de sumergirnos en las complejidades de los errores, entendamos el tipo never en sí. En TypeScript, este tipo denota "un valor que no puede existir". Suena filosófico, pero en la práctica es simple:
- \n
neveres el tipo para funciones que nunca terminan (bucle infinito) o siempre lanzan una excepción. \n neveres el "fondo" del sistema de tipos. Puede asignarnevera cualquier cosa, pero nada puede asignarse anever(excepto el propionever). \n
Ahora imagine que TypeScript ve un array vacío y no sabe qué elementos contendrá. En modo de tipificación estricta (strict: true en tsconfig.json), el compilador llega a una conclusión lógica: "Si el array está vacío y no se especifica el tipo, entonces no puede contener nada: el tipo de los elementos es never".
// Ejemplo: TypeScript infiere el tipo como never[]\nconst emptyArray = [];\nemptyArray.push("hello"); // ¡Error!\n// Argument of type 'string' is not assignable to parameter of type 'never'\n\n\nAhí está, el error en cuestión. TypeScript advierte honestamente: "Dijiste que el array solo puede contener never, pero intentas agregar una cadena. ¡Así no funciona!"
Escenarios principales de aparición del error
\n\n1. Array vacío sin anotación de tipo
\n\nEl caso más común. El desarrollador crea un array vacío, planeando llenarlo después, pero olvida especificar el tipo.
\n\n// ❌ Problema\nconst items = []; // TypeScript infiere: any[] (si strict: false) o never[] (si strict: true)\nitems.push({ id: 1, name: "Alice" }); // Error con strict: true\n\n// ✅ Solución: especifique el tipo explícitamente\nconst items: Array<{ id: number; name: string }> = [];\nitems.push({ id: 1, name: "Alice" }); // ¡Funciona!\n\n\n2. Métodos de arrays que devuelven never (filter, reduce)
\n\nEl método filter con un predicado incorrecto o reduce sin valor inicial pueden llevar a la inferencia del tipo never.
// ❌ Problema con filter\nconst numbers: (number | null)[] = [1, null, 2, null, 3];\nconst onlyNumbers = numbers.filter(item => item !== null); \n// TypeScript puede inferir el tipo como (number | null)[] o incluso never[], si el predicado está "roto"\n\n// ✅ Solución: use un type guard\nconst onlyNumbersSafe: number[] = numbers.filter((item): item is number => item !== null); \n\n// ❌ Problema con reduce\nconst result = [1, 2, 3].reduce((acc, val) => acc + val); \n// ¡Error! TypeScript no conoce el tipo inicial del acumulador\n\n// ✅ Solución: especifique el valor inicial\nconst resultSafe = [1, 2, 3].reduce((acc, val) => acc + val, 0); // ¡Funciona!\n\n\n3. Genéricos y tipos condicionales
\n\nUn caso más complejo: cuando TypeScript no puede inferir el tipo debido a generalizaciones complejas.
\n\n// ❌ Problema\nfunction getFirstElement<T>(arr: T[]): T | undefined {\n return arr[0];\n}\n\nfunction processItems<T>