从子类调用带有参数的回调



我的一个TypeSript函数有一些问题。我希望这不是一个绝对愚蠢的问题,但我相信我试图做的事情在理论上应该可行。

这是我的问题的简化版本。我希望它能显示问题发生的地方(原来的代码太多了(。

abstract class A {
name: string;
log(callback: (ev: A) => void) {}
constructor(name: string) {
this.name = name;
}
}
class B extends A {
addr: string;
constructor(addr: string, name: string) {
super(name);
this.addr = addr;
}
}
let b = new B("1", "2");
b.log((ev: B) => {});

问题出现在代码的最后一行。log函数是一个类型为A的回调函数。我想用B类型的属性来调用它。理论上,这应该是可行的,因为B extends A。但它显示了以下错误:

Argument of type '(ev: B) => void' is not assignable to parameter of type '(ev: A) => void'.
Types of parameters 'ev' and 'ev' are incompatible.
Property 'addr' is missing in type 'A' but required in type 'B'.(2345)
input.tsx(13, 5): 'addr' is declared here.

我不想在函数中强制转换ev参数。我希望你知道问题出在哪里,我的目标是什么。

祝你今天愉快。

这是一个正确的错误,与相反有关。

如果log的参数类型为A,则定义为:

abstract class A {
// ...
log(ev: A) { console.log(ev.name) };
//...
}

您可以从以下位置调用该函数:

let b = new B("1", "2");
b.log(b); // works fine, because `B` also has property `name`

这里有完整的例子。

但在传递全函数(ev: A) => void时,它与(ev: B) => void并不矛盾。例如,满足签名(ev: B) => void的函数可以是:

function (ev: B) {
console.log(ev.addr); // B specific, input parameter of type A would break!
}

如果在内部传递类型为Aev,则此函数将中断,因为A不包含属性addr,仅包含B。这就是打字脚本不允许你这么做的原因。

最新更新