Introduction : pourquoi TypeScript crie-t-il sur un tableau vide ?
\n\nAvez-vous déjà écrit du code en TypeScript, lancé la compilation, et reçu un message mystérieux : "Argument of type 'X' is not assignable to parameter of type 'never'" ? Si oui, vous n'êtes pas seul. Cette erreur est un véritable obstacle pour les développeurs de tous niveaux. Sur Stack Overflow, cette question a recueilli des milliers de vues, et aujourd'hui nous allons l'analyser une fois pour toutes.
Imaginez la situation : vous déclarez un tableau vide, essayez d'y ajouter quelque chose, et TypeScript bloque l'opération. Cela vous dit quelque chose ? Voyons pourquoi cela se produit et, surtout, comment le corriger.
\n\nDans cet article, nous ne nous contenterons pas de traduire une documentation aride. Nous suivrons le chemin depuis l'apparition de l'erreur jusqu'à sa résolution complète avec des exemples concrets que vous pourrez immédiatement appliquer dans vos projets.
\n\nQu'est-ce que le type never en TypeScript ?
\n\nAvant de plonger dans les méandres des erreurs, comprenons le type never lui-même. En TypeScript, ce type désigne "une valeur qui ne peut pas exister". Cela semble philosophique, mais en pratique c'est simple :
- \n
neverest le type pour les fonctions qui ne se terminent jamais (boucle infinie) ou qui lèvent toujours une exception. \n neverest le "fond" du système de types. Vous pouvez assignerneverà n'importe quoi, mais rien ne peut être assigné ànever(saufneverlui-même). \n
Imaginez maintenant que TypeScript voit un tableau vide et ne sait pas quels éléments il contiendra. En mode de typage strict (strict: true dans tsconfig.json), le compilateur fait une déduction logique : "Si le tableau est vide et que le type n'est pas spécifié, alors rien ne peut s'y trouver — le type des éléments est never".
// Exemple : TypeScript déduit le type comme never[]\nconst emptyArray = [];\nemptyArray.push("hello"); // Erreur !\n// Argument of type 'string' is not assignable to parameter of type 'never'\n\n\nVoilà, c'est cette fameuse erreur. TypeScript vous avertit honnêtement : "Tu as dit que le tableau ne peut contenir que never, mais tu essayes d'ajouter une chaîne. Ça ne marche pas !"
Scénarios principaux d'apparition de l'erreur
\n\n1. Tableau vide sans annotation de type
\n\nLe cas le plus fréquent. Le développeur crée un tableau vide, prévoyant de le remplir plus tard, mais oublie de spécifier le type.
\n\n// ❌ Problème\nconst items = []; // TypeScript déduit : any[] (si strict: false) ou never[] (si strict: true)\nitems.push({ id: 1, name: "Alice" }); // Erreur avec strict: true\n\n// ✅ Solution : spécifiez explicitement le type\nconst items: Array<{ id: number; name: string }> = [];\nitems.push({ id: 1, name: "Alice" }); // Fonctionne !\n\n\n2. Méthodes de tableau retournant never (filter, reduce)
\n\nLa méthode filter avec un prédicat incorrect ou reduce sans valeur initiale peuvent conduire à une déduction du type never.
// ❌ Problème avec filter\nconst numbers: (number | null)[] = [1, null, 2, null, 3];\nconst onlyNumbers = numbers.filter(item => item !== null); \n// TypeScript peut déduire le type comme (number | null)[] ou même never[], si le prédicat est "cassé"\n\n// ✅ Solution : utilisez un type guard\nconst onlyNumbersSafe: number[] = numbers.filter((item): item is number => item !== null); \n\n// ❌ Problème avec reduce\nconst result = [1, 2, 3].reduce((acc, val) => acc + val); \n// Erreur ! TypeScript ne connaît pas le type initial de l'accumulateur\n\n// ✅ Solution : spécifiez la valeur initiale\nconst resultSafe = [1, 2, 3].reduce((acc, val) => acc + val, 0); // Fonctionne !\n\n\n3. Génériques et types conditionnels
\n\nUn cas plus complexe — lorsque TypeScript ne peut pas déduire le type en raison de génériques complexes.
\n\n// ❌ Problème\nfunction getFirstElement<T>(arr: T[]): T | undefined {\n return arr[0];\n}\n\nfunction processItems<T>