TypeScript中Promise.all的类型推断原理是什么?自定义实现为何报错?
关于TypeScript对Promise.all的类型定义与自定义实现问题解答
内置Promise.all的类型推断原理
你看到的单泛型签名只是Promise.all的其中一个重载,TypeScript为了支持传入不同类型的Promise,实际上做了两层设计:
- 首先是针对固定长度的短元组做了专门的重载,比如2个、3个、4个参数的场景,每个重载都会单独匹配每个位置的Promise类型,精准返回对应类型的元组
- 对于更长的参数,TypeScript使用可变元组泛型做统一处理,会遍历传入的Promise元组的每一个位置,单独提取每个Promise的resolve值类型,最终把这些类型按原顺序组合成新的元组作为返回值的泛型参数
所以即使传入不同类型的Promise,TypeScript也能按位置推断出每一项的准确类型,不会把所有类型合并成联合类型。
自定义promiseAll报错的原因
你写的实现用了统一的泛型T来定义整个Promise数组的返回值类型:function<T>(promises: Promise<T>[]): Promise<T[]>,这就要求所有传入的Promise的resolve值必须是同一个类型。当你同时传入Promise<number>和Promise<string>时,TypeScript只能把T推断为number | string,返回值就变成了(number | string)[],和你预期的按位置匹配的[number, string]元组类型不符,自然会抛出类型错误。
自定义promiseAll的修复方案
把泛型改成可变元组形式,让TypeScript可以逐个匹配每个位置的Promise类型:
const promiseAll = function<T extends readonly unknown[]>(promises: [...{ [K in keyof T]: Promise<T[K]> }]): Promise<[...T]> { const results: unknown[] = []; let completedCount = 0; return new Promise(function (resolve, reject) { promises.forEach(function(promise, index) { promise.then(function (value) { results[index] = value; completedCount += 1; if(completedCount === promises.length) { resolve(results as T); } }).catch(function (error) { reject(error); }); }); }); }
修改后再调用promiseAll([promise1, promise2]),返回值就会被正确推断为Promise<[number, string]>,和内置Promise.all的表现完全一致。
内容的提问来源于stack exchange,提问作者dd345h
相关产品推荐
相关产品推荐

