我的一个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!
}
如果在内部传递类型为A
的ev
,则此函数将中断,因为A
不包含属性addr
,仅包含B
。这就是打字脚本不允许你这么做的原因。