为何TypeScript中需用双相同分支条件语句规避类型错误?
问题原因解析
1. 类型定义与async函数的核心特性
先明确类型StringToVoidOrNumsPromise的要求:
type StringToVoidOrNumsPromise = (arg0: string) => void | Promise<number[]>;
它规定函数必须返回**void或者Promise<number[]>**。但所有async函数有个本质特性:无论你返回什么值,最终都会被自动包装成Promise类型——哪怕返回void,实际返回的也是Promise<void>。
2. badFunc触发类型错误的根源
在badFunc中:
const oldResult = await sourceFunction(input); return oldResult;
sourceFunction(input)的返回类型是void | Promise<number[]>,经过await处理后:- 如果原返回是
void,await void等价于await undefined,最终oldResult的类型是undefined; - 如果原返回是
Promise<number[]>,await会解包得到number[]。
- 如果原返回是
- 因此
oldResult的实际类型是undefined | number[],被async函数包装后,最终返回类型变成Promise<undefined | number[]>。 - 这个类型无法匹配
StringToVoidOrNumsPromise的要求:Promise<undefined | number[]>既不是void,也不能赋值给Promise<number[]>(因为undefined | number[]与number[]类型不兼容),所以触发静态类型错误。
3. goodFunc通过类型检查的“侥幸”原因
goodFunc里的分支判断是关键:
if (oldResult instanceof Promise) { return oldResult; } else { return oldResult; }
这个判断在运行时永远为false(因为await已经把Promise<number[]>解包成了number[],oldResult不可能是Promise实例),但TypeScript的类型检查器被这个判断误导,做出了错误的类型收窄:
- 它认为
if分支中oldResult是Promise<number[]>,返回这个值时,async函数会自动解包,最终返回Promise<number[]>(符合类型要求); - 它认为
else分支中oldResult是void(排除Promise类型后,原联合类型剩下void),返回void时,async函数返回的Promise<void>被TypeScript判定为兼容void分支的要求。
本质上,goodFunc靠一个无意义的分支判断,让TypeScript误以为返回值是联合类型的两个独立成员,而非被统一包装的Promise联合类型,因此侥幸通过了类型检查。
内容的提问来源于stack exchange,提问作者fblundun
相关产品推荐
相关产品推荐

