Async/await y Array.map en TypeScript: 5 errores mortales

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Async/await y Array.map: cuando los mejores amigos se convierten en enemigos

\n\n

¿Alguna vez ha escrito algo como const results = await array.map(async (item) => {...}) y obtuvo un array de Promise en lugar de los datos esperados? Si es así, no está solo. Esta pregunta en Stack Overflow ha acumulado decenas de miles de visitas, y la cantidad de desarrolladores que han caído en este error se cuenta por millones.

\n\n

En este artículo analizaremos los 5 errores más peligrosos al usar async/await con Array.map en TypeScript. Y, lo que es más importante, le mostraré cómo evitarlos. Abróchese el cinturón: será doloroso, pero útil.

\n\n

Error n.º 1: Olvidar Promise.all (el más común)

\n\n

El error más común es pensar que await dentro de map esperará mágicamente a todas las promesas. Spoiler: no, no lo hará.

\n\n

El problema

\n
// ❌ Así no funciona\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 es Promise[], ¡no UserData[]!\nconsole.log(userData); // [Promise, Promise, Promise, Promise, Promise]
\n\n

¿Por qué ocurre esto?

\n

Array.map es síncrono. No espera a que los callbacks asíncronos terminen. Cada llamada a la función async devuelve una Promise, y map simplemente las agrupa en un array. await antes de map solo espera a que termine el propio map, pero no a sus callbacks.

\n\n

Solución

\n
// ✅ Correcto: envolvemos en 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 es UserData[]! 🎉\nconsole.log(userData);
\n\n

Error n.º 2: Todas las promesas se ejecutan en paralelo (cuando se necesita secuencial)

\n\n

Promise.all ejecuta todas las promesas en paralelo. Esto es genial para el rendimiento, pero a veces necesitamos ejecutar las solicitudes estrictamente una tras otra. Por ejemplo, al trabajar con una API que limita la cantidad de solicitudes, o cuando cada solicitud siguiente depende de la anterior.

\n\n

El problema

\n
// ❌ Todas las solicitudes se envían al mismo tiempo\nconst ids = [1, 2, 3, 4, 5];\nconst results = await Promise.all(\n  ids.map(async (id) => {\n    // 5 solicitudes a la API simultáneamente: se puede obtener un rate limit\n    return await api.processItem(id);\n  })\n);
\n\n

Solución: ejecución secuencial

\n
// ✅ Usamos for...of con 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 es un array con datos procesados en orden
\n\n

Una alternativa es Array.reduce con un acumulador de promesa:

\n
// ✅ También funciona, pero es menos legible\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

Error n.º 3: Tipado incorrecto en TypeScript

\n\n

TypeScript puede no entender de inmediato lo que está haciendo con un map asíncrono. Especialmente si usa Promise.all sin especificar explícitamente el tipo.

\n\n

El problema

\n
// ❌ TypeScript se queja o deduce un tipo incorrecto\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 podría pensar que es Promise<string>\n  })\n);\n// results tiene tipo unknown o Promise<string>[]
\n\n

Solución: anotación de tipo explícita

\n
// ✅ Especificamos explícitamente el tipo de resultado                

Blogs

Book Recommendations