【问题标题】:Base class return reference to extended class type mismatch基类返回对扩展类类型不匹配的引用
【发布时间】:2018-06-17 17:57:39
【问题描述】:

我有一个基类的简化版本,它应该是树结构的一个节点,并持有对其父级的引用。

class Node {
  parent: Node;

  setParent(a: Node) {
    this.parent = a;
  }

  getParent(): Node {
    return this.parent;
  }
}

派生类为基本节点添加了更多功能

class NamedNode extends Node {
  name: string;

  setName(name: string) {
    this.name = name;
  }
}

我使用派生类创建我的小树,并通过调用setParent 将对父级的引用存储在子级中,然后通过调用getParent 从子级检索父级。

const parent = new NamedNode();

const child = new NamedNode();
child.setParent(parent);

const parentOfChild = child.getParent();

parentOfChild.setName('foo');

当我在检索到的父级上调用 setName 时,即使它是 NamedNode 的实例,TypeScript 也会引发错误

类型“节点”上不存在属性“setName”。

我可以理解,因为方法签名getParent(): Node 明确定义它只返回Node 的实例并且它没有setName 方法。

我的问题是如何让getParent 返回Node 的一个实例,所以我知道返回值将具有Node 的方法,但同时它应该可以扩展,所以我将能够在没有 TypeScript 抱怨的情况下调用返回值的后代方法。我的目标是每个后代节点类都有Node 方法,然后这些后代类的实例可以在Node 基类中用作parent 引用。我还想避免在派生类中重写Node 方法来更新Node 方法签名,因为继承方法重用的全部意义将不复存在。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用this 作为类型,表示当前类的类型,这样在派生类中parent 将与派生类具有相同的类型:

    export class Node {
        parent: this;
    
        setParent(a: this) {
            this.parent = a;
        }
    
        getParent(): this {
            return this.parent;
        }
    }
    
    class NamedNode extends Node {
        name: string;
    
        setName(name: string) {
            this.name = name;
        }
    }
    
    
    const parent = new NamedNode();
    
    const child = new NamedNode();
    child.setParent(parent);
    
    const parentOfChild = child.getParent();
    
    parentOfChild.setName('foo');
    

    语言的这个特性被称为多态this,你可以在docsPR了解更多信息

    【讨论】:

    • 谢谢,这正是我所需要的。对 TS 的所有功能有点不知所措,并且在文档中还没有达到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多