在 TypeScript 中多态 this

Mic*_*ler 5 typescript

我正在尝试做我认为是多态的“教科书”用例this,但它不起作用,我只是想不通。想象一下,我有一些abstract可克隆的基类,例如:

abstract class X {
    abstract clone(): this;
}
Run Code Online (Sandbox Code Playgroud)

现在我想实现一个提供实现的基类clone

class Y extends X {
    constructor(private x: number) { super() }
    clone(): this { return new Y(this.x + 1); }
}
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我收到一个错误消息Type Y is not assignable to type 'this'。我完全糊涂了。我想在这里传达的是类型约束,如果 的子类调用了X它的clone方法,那么您将返回的事物的类型将与子类型相同。这不正是多态this的用途吗?我在这里做错了什么?

这是TypeScript 游乐场中此代码的链接

Mic*_*ler 5

我已将 artem 的答案标记为正确的答案,因为他似乎是正确的,确实不可能以 100% 安全的方式做到这一点。

但是,有一种方法可以让编译器强制执行我想要的类型约束。因此,我决定包含这个答案,以防它对人们有用。我的方法的唯一缺点是它有点不安全,这正是 artem 指出的原因,即有人可以在不提供实现的情况下扩展你的类,clone并创建一种返回值实际上不是你所声明的值的情况是。

我的解决方案是只添加一个演员。同样,这通常是不安全的。但如果你从不离开课堂,据我所知,它工作得很好。所以我的解决方案是:

class Y extends X {
    constructor(private x: number) { super() }
    clone(): this {
        return new Y(this.x + 1) as this;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看编译的完整版本。


art*_*tem 4

不,就目前情况而言,它不是此类型支持的用例。具有返回类型的方法this应该返回派生类的实例,即使该方法没有在派生类中重写 - 请参阅此答案中的代码以获取证明这一点的示例。

换句话说,给定abstract clone(): this声明,即使 Z 没有覆盖clone自身,但您的clonein实现Y破坏了它,此代码也必须有效。

class Z extends Y {
    f() {
        let c: Z = this.clone();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以看起来this应该总是有返回类型的方法return this

更新:我在 github 上发现了此用例的一个未解决问题,标记为“接受拉取请求”。但我不确定他们是否真的打算支持它,或者计划cloneNode以其他方式修复他们的编译器。