升级TypeScript至3.7.4后出现TS2339编译错误求助
我刚帮你捋清楚这个问题——从TS 3.4.1升级到3.7.4后,Promise.all的类型推断逻辑发生了变化,这才导致了这个编译错误。先复盘下你的场景:
你的配置与代码
tsconfig.json:
{ "compilerOptions": { "baseUrl": ".", "outDir": "dist", "module": "commonjs", "target": "es6", "experimentalDecorators": true, "emitDecoratorMetadata": true, "sourceMap": true } }
可复现代码:
async function f1(): Promise<{a: number}> { return Promise.resolve({} as any); } async function f2(): Promise<{a: number, b: number}> { return Promise.resolve({} as any); } (async ()=> { const tp = await Promise.all([f1(), f2()]); let a = tp[0].a; let b = tp[1].a; let c = tp[1].b; // 这里报错:Property 'b' does not exist on type '{ a: number; }' console.log(a, b, c); })();
问题原因
在TS 3.4.1中,Promise.all([f1(), f2()])会被推断为Promise<[{a: number}, {a: number, b: number}]>(元组类型),所以tp[1]的类型明确是{a: number, b: number},访问b不会有问题。
但TS 3.7.4对数组字面量的类型推断做了调整:当你传递普通数组给Promise.all时,它会默认把数组推断为联合类型的数组,也就是Promise<({a: number} | {a: number, b: number})[]>。这时候tp[1]的类型是{a: number} | {a: number, b: number},TS无法确定它一定包含b属性,所以抛出了编译错误。
解决方案
这里有几种简单的修复方式,选你觉得最顺手的就行:
方案1:用as const断言数组为元组
给Promise.all的参数加上as const,强制TS把数组推断为元组类型,这样返回值的类型就会保留每个Promise的具体返回类型:
const tp = await Promise.all([f1(), f2()] as const);
方案2:显式指定Promise.all的泛型参数
直接告诉TSPromise.all的返回元组类型,明确每个位置的类型:
const tp = await Promise.all<[{a: number}, {a: number, b: number}]>([f1(), f2()]);
方案3:给tp变量显式指定类型
如果不想修改Promise.all的调用,也可以直接给tp变量声明元组类型:
const tp: [{a: number}, {a: number, b: number}] = await Promise.all([f1(), f2()]);
这三种方法都能让TS正确识别tp[1]的类型,解决Property 'b' does not exist的错误。
内容的提问来源于stack exchange,提问作者BaolingWang

