以下代码可以正常编译
interface W {
x: string;
}
interface M {
x: string;
}
type D<N extends M> = N | W;
declare function a<N extends M, Q extends D<N> = D<N>>(): Q | Q[] | undefined;
declare function b<N extends M, Q extends D<N> = D<N>>(p?: Q | Q[]): void;
const x = a();
b(x);
当我将函数b
放在类中时,事情会变得有趣:
export class C<N extends M, Q extends D<N>> {
f(p?: Q | Q[]): void {}
g() {
const y = a();
this.f(a());
this.f(y);
}
}
在这里,C.f
应该等效于功能b
。但是,在行this.f(y)
上出现类型错误。有趣的是,行this.f(a())
可以正常编译。
Argument of type 'W | M | (W | M)[] | undefined' is not assignable to parameter of type 'Q | Q[] | undefined'.
Type 'W' is not assignable to type 'Q | Q[] | undefined'.
Type 'W' is missing the following properties from type 'Q[]': length, pop, push, concat, and 28 more.
我不明白此错误,因为类型Q
应该等效于W | N
,所以如何不能将W
分配给Q
?
答案 0 :(得分:1)
差异是由于在函数上具有类型参数,而在类上具有类型参数。为了简化答案,我将删除Q[]
,a
和b
上的f
选项,因为没有它也会表现出相同的行为。
在分配x = a()
中,Typescript需要为变量x
推断类型。这需要为类型变量N
和Q
选择具体的类型;在没有其他约束的情况下,将选择其上限,因此x
的类型为M | W | undefined
。这里的重点是,编译器可以自由选择上限D<M>
作为Q
的具体类型。
然后,在调用b(x)
中,Typescript可以自由选择N = M
和Q = D<M>
,因此不会出现类型错误。
在该类中,分配y = a()
与上面的内容完全相同,因此y
的类型为M | W | undefined
。但是,然后在对f(y)
的调用中,Typescript不能自由选择N = M
和Q = D<M>
,因为这些N
和{{1} }是类的类型参数。在这里无法推断出Q
和N = M
,因为有人:
Q = D<M>
并创建一个class M2 implements M { ... }
对象。C<M2, D<M2>>
并创建一个type D2<N extends M> = D<N> & { ... }
对象。因此,在呼叫C<M, D2<M>>
中,将类型f(y)
的{{1}}分配给类型y
的{{1}}的参数是不安全的,因为当M | W | undefined
或f
或其他内容时,变量Q
不是Q = D<M2>
或Q = D2<M>
的子类型。