Async/await et Array.map en TypeScript : 5 erreurs fatales

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Async/await et Array.map : quand les meilleurs amis deviennent ennemis

\n\n

Avez-vous déjà écrit quelque chose comme const results = await array.map(async (item) => {...}) et obtenu un tableau de Promise au lieu des données attendues ? Si oui, vous n'êtes pas seul. Cette question sur Stack Overflow a recueilli des dizaines de milliers de vues, et le nombre de développeurs qui sont tombés dans ce piège se compte par millions.

\n\n

Dans cet article, nous allons analyser les 5 erreurs les plus dangereuses lors de l'utilisation de async/await avec Array.map en TypeScript. Et, plus important encore, je vais vous montrer comment les éviter. Attachez votre ceinture — ça va faire mal, mais c'est utile.

\n\n

Erreur n°1 : Oublier Promise.all (la plus courante)

\n\n

Le bug le plus fréquent est de penser que await à l'intérieur de map attendra magiquement toutes les promesses. Spoiler : non, ce n'est pas le cas.

\n\n

Le problème

\n
// ❌ Ça ne fonctionne pas\nconst users = [1, 2, 3, 4, 5];\nconst userData = await users.map(async (id) => {\n  const response = await fetch(`/api/users/${id}`);\n  return response.json();\n});\n// userData est Promise[], pas UserData[]!\nconsole.log(userData); // [Promise, Promise, Promise, Promise, Promise]
\n\n

Pourquoi cela se produit-il ?

\n

Array.map est synchrone. Il n'attend pas la fin des callbacks asynchrones. Chaque appel de fonction async retourne une Promise, et map les rassemble simplement dans un tableau. await avant map attend seulement la fin de map lui-même, mais pas de ses callbacks.

\n\n

La solution

\n
// ✅ Correct : on enveloppe dans Promise.all\nconst users = [1, 2, 3, 4, 5];\nconst userData = await Promise.all(\n  users.map(async (id) => {\n    const response = await fetch(`/api/users/${id}`);\n    return response.json();\n  })\n);\n// userData est UserData[]! 🎉\nconsole.log(userData);
\n\n

Erreur n°2 : Toutes les promesses s'exécutent en parallèle (alors qu'il faut le faire en séquence)

\n\n

Promise.all lance toutes les promesses en parallèle. C'est génial pour les performances, mais parfois nous devons exécuter les requêtes strictement l'une après l'autre. Par exemple, lorsqu'on travaille avec une API qui limite le nombre de requêtes, ou lorsque chaque requête suivante dépend de la précédente.

\n\n

Le problème

\n
// ❌ Toutes les requêtes partent en même temps\nconst ids = [1, 2, 3, 4, 5];\nconst results = await Promise.all(\n  ids.map(async (id) => {\n    // 5 requêtes simultanées à l'API — risque de rate limit\n    return await api.processItem(id);\n  })\n);
\n\n

Solution : exécution séquentielle

\n
// ✅ Utilisation de for...of avec await\nconst ids = [1, 2, 3, 4, 5];\nconst results: ItemData[] = [];\n\nfor (const id of ids) {\n  const result = await api.processItem(id);\n  results.push(result);\n}\n// results — tableau de données traitées dans l'ordre
\n\n

Une alternative — Array.reduce avec un accumulateur de promesse :

\n
// ✅ Fonctionne aussi, mais moins lisible\nconst ids = [1, 2, 3, 4, 5];\nconst results = await ids.reduce(async (accPromise, id) => {\n  const acc = await accPromise;\n  const result = await api.processItem(id);\n  return [...acc, result];\n}, Promise.resolve([] as ItemData[]));
\n\n

Erreur n°3 : Typage incorrect en TypeScript

\n\n

TypeScript peut ne pas comprendre immédiatement ce que vous faites avec un map asynchrone. Surtout si vous utilisez Promise.all sans spécifier explicitement le type.

\n\n

Le problème

\n
// ❌ TypeScript râle ou déduit un type incorrect\nconst ids = [1, 2, 3];\nconst results = await Promise.all(\n  ids.map(async (id) => {\n    const data = await fetchData(id);\n    return data.name; // TypeScript peut penser que c'est Promise<string>\n  })\n);\n// results a le type unknown ou Promise<string>[]
\n\n

Solution : annotation de type explicite

\n
// ✅ On spécifie explicitement le type du résultat                

Blogs

Book Recommendations