【问题标题】:Create instance from base class and maintain typings从基类创建实例并维护类型
【发布时间】:2021-02-19 17:06:56
【问题描述】:

我在尝试让基类推断父类的类型时遇到问题

abstract class Record {

    //...

    static findRecord(id: number){
        // this creates will create an instance of the prototype "this"
        // prototype of "this" will equal Node later
        return new (Object.getPrototypeOf(this))(id)
    }
}

class Node extends Record {
  statements(): Array<Statement> {
     // ...
  }
}

let node = Node.findRecord(1)
// type is "any" (as findRecord doesn't infer the type as "Node", because Object.getPrototypeOf(this)) can equal anything)

node.statements() // This has no typings in vscode

我希望 typescript 知道 Record 的类型将是实例化它的类(在本例中为 Node)

我需要实例化node 的类型为Node,以便.statements() 的类型可用,并且我想避免重复代码并且必须将其放入从@987654326 扩展的每个类中@。

【问题讨论】:

标签: typescript


【解决方案1】:

回答

根据@Titian 的回答here,您需要将findRecord 方法变成一个泛型函数,其中T 描述了特定的类实例。您使用this 参数作为忽略的第一个参数,以便打字稿可以在您调用它时根据this 的值推断T 的类型。

abstract class MyRecord {

    constructor(id: number) {
    }

    static findRecord<T>(this: new (id: number) => T, id: number): T {
        return new this(id);
    }
}

Typescript Playground Link

另一种方法

就我个人而言,我已经接受了“继承是不好的”的口头禅,所以我会将共享的 static 逻辑移动到一个单独的类中,该类可以通过将该记录的类作为参数传递给构造函数来为每个记录类型实例化。

class RecordFinder<T extends BaseRecord> {

    private readonly recordClass: RecordConstructor<T>;

    constructor( recordClass: RecordConstructor<T> ) {
        this.recordClass = recordClass;
    }

    find(id: number): T {
        return new this.recordClass(id);
    }
}

interface BaseRecord {
    id: number;
}

type RecordConstructor<T extends BaseRecord> = new (id: number) => T;

这里我是根据接口来限制recordClass的类型,所以MyNode是否扩展MyRecord无关紧要。

const nodeFinder = new RecordFinder(MyNode);

const node = nodeFinder.find(1);

Typescript Playground Link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-02
    • 2014-09-29
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多