已在Promise.all中赋值仍提示Variable is used before being assigned错误
问题描述
我有两个相互独立的异步方法,希望并行执行以节省时间,但后续步骤需要等待两者的返回值。我的代码如下:
public async methodOne(): Promise<MyObjectOne> { ... do something interesting return one; } public async methodTwo(): Promise<MyObjectTwo> { ... do something interesting return two; } public useVariables(one: MyObjectOne, two: MyObjectTwo) { ... do some useful work } public async runTogether(): Promise<void> { let one: MyObjectOne; let two: MyObjectTwo; await Promise.all([this.methodOne(), this.methodTwo()]) .then((values: [MyObjectOne, MyObjectTwo]) => { values.map((value: MyObjectOne | MyObjectTwo) => { if (value instanceof MyObjectOne) { one = value; } else { two = value; } }); }) .catch((error) => { throw new Error('There was an error'); }); this.useVariables(one, two); }
按照我的理解,执行到this.useVariables(one, two);时,要么两个变量已完成赋值,要么程序已抛出错误,但IDE却对两个变量均提示Variable 'one/two' is used before being assigned。我可以在使用变量前检查undefined来消除该错误,但想知道这个提示是否意味着我遗漏了某些逻辑,或是IDE无法识别变量已被赋值?另外有没有更优的并行执行这两个方法的实现方式?
解答
一、IDE提示未赋值的原因
这是TypeScript静态类型分析的局限性导致的:
- TypeScript无法深入追踪
map循环内部的条件判断逻辑,它没办法确定instanceof的分支一定会给one和two都完成赋值(虽然从业务逻辑上我们能保证,但静态分析做不到这么精准)。 - 另外,通过
then回调赋值变量的方式,让TypeScript难以确认变量在回调执行后必然被赋值,所以会触发“未赋值即使用”的警告。
二、更优的并行执行实现方式
直接利用Promise.all的返回值顺序特性,结合async/await的解构语法,就能彻底解决这个问题,代码也更简洁易读:
public async runTogether(): Promise<void> { try { // 直接解构Promise.all的返回结果,顺序与传入的Promise完全对应 const [one, two] = await Promise.all([this.methodOne(), this.methodTwo()]); this.useVariables(one, two); } catch (error) { throw new Error('There was an error'); } }
这个写法的优势:
- 类型安全且无警告:TypeScript能准确推断出
one是MyObjectOne类型、two是MyObjectTwo类型,不会再有未赋值的提示。 - 代码更简洁:省去了多余的
map遍历和类型判断,直接利用Promise.all的顺序性(传入的第一个Promise的结果会放在返回数组的第一个位置,以此类推)。 - 符合async/await最佳实践:用
try/catch替代then/catch,代码逻辑更线性,可读性更强。
内容的提问来源于stack exchange,提问作者Steven
相关产品推荐
相关产品推荐

