为何Promise.allSettled+forEach后TypeScript将值推断为never类型?
问题原因
TypeScript的控制流分析无法跨函数回调跟踪变量赋值,这是核心问题。
你用Array.forEach()处理Promise.allSettled的结果时,forEach的回调是一个独立函数。TypeScript无法确保这个回调会被执行(即便我们明确知道数组有2个元素、回调会执行2次,但TS的静态分析不会做这么深入的假设),因此它无法识别到回调里对value和value2的赋值操作。
在后续的if (!value || !value2) throw检查中,TS会认为value和value2始终是初始的undefined,因此这个throw语句永远会触发,后面的代码属于不可达代码,变量类型就被推断为never。
解决方案
不用forEach,改用普通for循环或者直接解构allSettled的结果,让TS能跟踪控制流:
方案1:普通for循环
把forEach替换成索引循环或for...of,TS能直接跟踪循环内的变量赋值:
type myValue = { test1: string; test2: string; test3: string; } | undefined; const go = async () => { let value: myValue = undefined; let value2: myValue = undefined; const results = await Promise.allSettled([ Promise.resolve({test1: 'test1.1', test2: 'test2.1', test3: 'test3.1'}), Promise.resolve({test1: 'test1.2', test2: 'test2.2', test3: 'test3.2'}), ]); // 改用索引循环 for (let index = 0; index < results.length; index++) { const result = results[index]; if (result.status === "fulfilled") { if (index === 0) { value = result.value; } if (index === 1) { value2 = result.value; } } else { console.error("error", result.reason); } } if (!value || !value2) { throw new Error("no Value found"); } // TS现在能正确推断类型 console.log("value.test1:", value.test1); console.log("value2.test3:", value2.test3); } go();
方案2:直接解构结果
既然你明确知道数组有2个元素,直接解构allSettled的结果,更简洁且TS能完美推断:
type myValue = { test1: string; test2: string; test3: string; } | undefined; const go = async () => { const [result1, result2] = await Promise.allSettled([ Promise.resolve({test1: 'test1.1', test2: 'test2.1', test3: 'test3.1'}), Promise.resolve({test1: 'test1.2', test2: 'test2.2', test3: 'test3.2'}), ]); let value: myValue = undefined; let value2: myValue = undefined; if (result1.status === "fulfilled") { value = result1.value; } else { console.error("error in result1", result1.reason); } if (result2.status === "fulfilled") { value2 = result2.value; } else { console.error("error in result2", result2.reason); } if (!value || !value2) { throw new Error("no Value found"); } console.log("value.test1:", value.test1); console.log("value2.test3:", value2.test3); } go();
补充说明
TS的控制流分析是局部性的,它不会跨函数调用跟踪变量状态。类似forEach、map这类接受回调的数组方法,TS都无法识别回调内对外部变量的修改。改用同步的循环结构(for、for...of)或者直接处理每个元素,就能让TS正确推断类型,不需要类型断言或忽略错误。
内容的提问来源于stack exchange,提问作者hcbd
相关产品推荐
相关产品推荐

