为何Promise<A | B>无法赋值给Promise<A> | Promise<B>?
TypeScript中Promise联合类型的赋值兼容性问题
type A = Promise<string> | Promise<number> type B = Promise<string | number> const a: A = Math.random() > 0.5 ? Promise.resolve('string') : Promise.resolve(1) const b: B = Promise.resolve(Math.random() > 0.5 ? 'string' : 1) class C { fa(a: A) { console.log(a) } fb(b: B) { console.log(b) } } const c = new C() c.fa(a) c.fb(b) c.fa(b) /* <-- 此处报错: Argument of type 'B' is not assignable to parameter of type 'A'. Type 'Promise<string | number>' is not assignable to type 'Promise<string>'. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.ts(2345) */ c.fb(a) // 此处可正常运行
问题
为什么代码中c.fa(b)会出现类型赋值错误,而c.fb(a)可正常执行?
解答
核心差异在于A和B两个类型的本质:
A是两个明确Promise类型的联合:它代表的是一个二选一的Promise——要么是只能resolve字符串的Promise<string>,要么是只能resolve数字的Promise<number>,二者必居其一。B是单个Promise包裹着联合类型:它是一个不确定的Promise,最终resolve的值可能是字符串,也可能是数字,无法提前确定具体类型。
1. 为什么c.fb(a)可以正常执行?
a的类型是A,也就是要么是Promise<string>,要么是Promise<number>。TypeScript中Promise的泛型是协变的:如果泛型参数X是Y的子类型,那么Promise<X>可以赋值给Promise<Y>。
string是string | number的子类型,所以Promise<string>能赋值给Promise<string | number>;number也是string | number的子类型,所以Promise<number>也能赋值给Promise<string | number>。
既然A的两个分支都兼容B,那整个A类型自然可以传递给fb方法的参数。
2. 为什么c.fa(b)会报错?
b的类型是B,也就是Promise<string | number>。而fa方法要求的参数是A——要么是纯字符串Promise,要么是纯数字Promise。但b这个Promise既可能返回字符串,也可能返回数字,它既不符合Promise<string>的要求(因为存在返回数字的可能),也不符合Promise<number>的要求(因为存在返回字符串的可能),所以无法赋值给A类型,TypeScript就会抛出类型不兼容的错误。
内容的提问来源于stack exchange,提问作者Emil Ivanov
相关产品推荐
相关产品推荐

