【问题标题】:Callbacks with parameter from subclass带有子类参数的回调
【发布时间】:2021-08-09 23:55:05
【问题描述】:

我的一个 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 参数。我希望你能找到问题所在以及我的目标是什么。

祝你有美好的一天。

【问题讨论】:

  • 您到底想要一个接受回调并向其提供对象本身的方法?大概如果您可以调用该方法,则您已经拥有对该对象的引用。如果需要,您可以致电 b((_: any) => console.log(b.addr))。对象接受一个将被同一个对象调用的回调似乎有点多余。除非它不是同一个,而是同一个类的不同实例,但调用instance1.log((thisWillBeInstance2 => {}) 似乎仍然很奇怪。
  • "理论上,这应该可行,因为 B 扩展了 A" - 不。允许log 方法传递B 实例而不是A 实例,但不允许回调声明它只接受B 实例而不接受任何A。请向我们展示log 的实际实现,以便我们推荐正确的输入方法。

标签: javascript typescript function oop callback


【解决方案1】:

这是正确的错误,与逆变有关。

如果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`

你有完整的例子here

但是当传递全函数(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。这就是 typescript 不允许你这样做的原因。

【讨论】:

  • 我想调用传递给log的函数作为回调。如果我将log 的参数更改为对象而不是函数,则它不再是回调。所以它必须是一个函数。
  • 您错过了重点 - 您的 log 回调在两个类上的有效签名是 (ev: A) => void。然后您可以在您的B 实现中将您的B 实例传递给它。
猜你喜欢
  • 1970-01-01
  • 2021-01-22
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-25
  • 2019-12-16
相关资源
最近更新 更多