类似的代码:
class A {
static foo<T extends A>() {
return {} as T;
}
}
class B extends A {
bar!:number
static foo<T extends B>() {
return {} as T;
}
}
错误是:
Class static side 'typeof B' incorrectly extends base class static side 'typeof A'.
Types of property 'foo' are incompatible.
Type '<T extends B>() => T' is not assignable to type '<T extends A>() => T'.
Type 'B' is not assignable to type 'T'.
'B' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'A'.
答案 0 :(得分:1)
无论好坏,TypeScript都会强制执行the static side of a subclass should be compatible with the static side of its superclass。这意味着您应该能够从子类中substitute用同名的属性/方法{超类的静态属性/方法而不会出现错误。 (好吧,除了构造函数签名外,有意免除此规则,以允许子类构造函数从其超类采用不同的参数)。 尚不清楚每个人是否都希望这样做(请参见relevant comment),但事实就是这样。
无论如何,这意味着如果您具有以下代码,
// some subtype of A that does not extend B
class C extends A {
baz = 123;
}
let aFoo = A.foo;
aFoo<C>().baz; // number, okay
您必须能够用A.foo
代替B.foo
并使其仍然起作用:
let aFoo = B.foo;
aFoo<C>().baz; // error! C does not extend B
但事实并非如此。您的B.foo()
定义不允许使用类型C
的类型参数,因为C
不扩展B
。因此无法使用B.foo
代替A.foo
,因此B
不能正确扩展A
。这就是为什么您会得到一个错误。
不确定如何为您进行最佳处理。如果这是实例方法而不是静态方法,则建议您使用polymorphic this
types表示“当前”类。但是有no such types available to static methods,所以这不是一个选择。
一种可行的解决方法是通过在运行时几乎没有帮助的辅助函数来显式扩展类的静态方面,并对其进行扩展:
function OmitStatic<T extends new (...args: any) => any, K extends keyof T>(
ctor: T, ...k: K[]
): Omit<T, K> & (new (...args: ConstructorParameters<T>) => InstanceType<T>) {
return ctor;
}
您将像这样使用它:
class A {
static foo<T extends A>() {
return {} as T;
}
}
// note how we extend OmitStatic(A, "foo") instead of A
class B extends OmitStatic(A, "foo") {
bar!: number
static foo<T extends B>() {
return {} as T;
}
}
我们仍然具有实例端兼容性:
let b = new B();
let a = new A();
a = b; // okay, instance side is still substitutable
虽然静态端的行为符合您的要求,但B
的定义内没有任何错误:
class C extends A {
baz = 123;
}
A.foo<C>(); // okay
B.foo<C>(); // not okay
好的,希望能有所帮助;祝你好运!