解决TS报错:Promise<any[]>无法赋值给readonly unknown[]参数
TypeScript 异步代码类型报错修复
问题代码
async function fetchData() { xlData.map(async (student, id) => { const studentExist = await User.findOne({ email: student.email, }); if (studentExist) { let includesStudent = await Class.findOne({ student: { $in: [studentExist._id] }, }); if (!includesStudent) { studentsIds.push(studentExist._id); } } }); return studentsIds; } const finalData: any[] = await Promise.all(fetchData()); console.log("final data", finalData);
运行后抛出如下TS错误:
No overload matches this call. Overload 1 of 2, '(values: readonly unknown[] | []): Promise<unknown[] | []>', gave the following error. Argument of type 'Promise<any[]>' is not assignable to parameter of type 'readonly unknown[] | []'. Type 'Promise<any[]>' is not assignable to type '[]'. Overload 2 of 2, '(values: Iterable<any>): Promise<any[]>', gave the following error. Argument of type 'Promise<any[]>' is not assignable to parameter of type 'Iterable<any>'. Property '[Symbol.iterator]' is missing in type 'Promise<any[]>' but required in type 'Iterable<any>'.ts(2769)
报错原因
- 直接类型错误:
Promise.all的入参要求是 由Promise组成的可迭代对象(通常是Promise数组),但fetchData本身是async函数,调用后会返回单个Promise<any[]>,把单个Promise作为入参传给Promise.all完全不符合参数类型要求,直接触发TS类型校验失败。 - 隐藏逻辑错误:
xlData.map传入异步回调时,会立即返回一个Promise数组,原代码没有等待这组异步数据库查询执行完成,就直接返回了外部的studentsIds数组,就算绕过TS校验,实际运行时也大概率拿到空数组,因为异步操作还没执行完就已经返回结果了。
修复方案
核心修正两点:
- 把
Promise.all放到fetchData内部,用来等待map生成的所有异步查询任务执行完成,再返回结果 - 外部调用
fetchData时直接加await即可,不需要额外套一层Promise.all
推荐写法(避免外部变量push带来的副作用,更易维护):
async function fetchData() { // 等待所有学生的查询任务全部执行完成 const rawResults = await Promise.all( xlData.map(async (student) => { const studentExist = await User.findOne({ email: student.email, }); if (!studentExist) return null; const isInClass = await Class.findOne({ student: { $in: [studentExist._id] }, }); return isInClass ? null : studentExist._id; }) ); // 过滤掉不符合条件的null值,得到最终学生ID数组 return rawResults.filter((id): id is InstanceType<typeof User>['_id'] => !!id); } // 直接await调用即可,无需额外套Promise.all const finalData = await fetchData(); console.log("final data", finalData);
如果要保留原有push的写法,可参考如下实现:
async function fetchData() { const studentsIds = []; // 等待所有异步查询执行完再往下走 await Promise.all( xlData.map(async (student) => { const studentExist = await User.findOne({ email: student.email, }); if (studentExist) { const includesStudent = await Class.findOne({ student: { $in: [studentExist._id] }, }); if (!includesStudent) { studentsIds.push(studentExist._id); } } }) ); return studentsIds; } const finalData = await fetchData(); console.log("final data", finalData);
内容的提问来源于stack exchange,提问作者Upendra Dhamala
相关产品推荐
相关产品推荐

