我有一个类,它包含一个成员,该成员是一个函数,它接受类的一个实例:
class Super {
public member: (x: Super) => void = function(){}
use() {const f = this.member; f(this)}
}
但我希望成员是逆变量;具体地说,我希望允许子类实例接受member
个值,这些值是接受特定子类的函数,即:
class Sub extends Super {
method() {}
}
const sub = new Sub();
sub.member = function(x: Sub) {x.method()};
但台积电相当正确地抱怨道:
Type '(x: Sub) => void' is not assignable to type '(x: Super) => void'.
Types of parameters 'x' and 'x' are incompatible.
Property 'method' is missing in type 'Super' but required in type 'Sub'.
如何在子类中声明member
,使其成为接受协变(而不是逆变)参数类型的函数?
我试过的是:
-
我知道如果我使用方法语法(
member(s: Super) {/* ... */}
)声明member
,那么它将是双变量的,但这对member
可能是函数集合的情况没有帮助(例如,在我的实际代码中,member
的类型是这样的函数的字典:{[name: string]: (/*...*/, s: Super) => /*...*/}
). -
我try 使用更严格的签名重新声明
Sub
中的member
:class Sub extends Super { public member: (x: Sub) => void = function(x){x.method()}; method() {} }
但台积电坚决不让我把枪对准我的脚:
Property 'member' in type 'Sub' is not assignable to the same property in base type 'Super'. Type '(x: Sub) => void' is not assignable to type '(x: Super) => void'. Types of parameters 'x' and 'x' are incompatible. Property 'method' is missing in type 'Super' but required in type 'Sub'.
-
我理解这typescript now supports
in
andout
modifiers on templates to denote co/contravariance个,但我不确定它们是否适用,也不确定如何将Super
变成一个适当的模板声明. -
我不想关闭
strictfunctionTypes
,因为它通常很有用,我不想强迫这个库的用户关闭它,以便在子类实例上分配给.member
. -
作为最后的手段,我可以将赋值转换为
as (x: Super) => void
, 但这消除了防止分配给错误的子类的保护,例如:class Sub1 extends Super { method1() {} } class Sub2 extends Super { method2() {} } const sub1 = new Sub1(); sub1.member = function(x: Sub2) {x.method2()} as (x: Super) => void;
被TSC接受,但在运行时失败.
-
判断相关的问题,我看到a similar question involving interfaces而不是子类,但它还没有正式的答案,我也不完全理解注释中链接的片段;它们似乎依赖于能够完全枚举所有子类型,这不适合我的情况,因为可能有任意数量的(子)*子类.