从通用到特定类型

时间:2017-08-02 23:19:52

标签: typescript generics

我想扩展一个类,并将其动态类型折叠为特定类型(从TPerson)。

我为这个例子创建了虚拟类:

class Person {
    constructor(public name: string){}
}

class Base<T> {
    reference?: T
    name: string

    constructor(name: string) {
        //  Assign properties from T to this
        this.name = name
    }

    static fromObject<T extends { name: string }>(object: T){
        const base = new Base(object.name)
        base.reference = object
        return base
    }
}

class Master<T> extends Base<T> {

    static fromBase<T>(base: Base<T>){
        const master = new Master(base.name)
        master.reference = base.reference
        return master
    }

    static fromObject<T extends { name: string }>(object: T){
        return Master.fromBase(Base.fromObject(object))
    }
}

class PersonMaster extends Master<Person>  {

    constructor(person: Person){
        super(person.name)
        this.reference = person
    }

    static fromBase(base: Base<Person>){
        return new PersonMaster(base)
    }
}

编译器返回此错误:

类静态端typeof PersonMaster错误地扩展了基类静态端typeof Master。属性类型fromBase不兼容。类型(base: Base<Person>) => PersonMaster不能分配<T>(base: Base<T>) => Master<{}>类型。参数类型basebase不兼容。类型Base<T>无法分配给Base<Person>。类型T不能分配Person类型。

1 个答案:

答案 0 :(得分:1)

fromBaseMaster的声明是通用的:

static fromBase<T>(base: Base<T>)

这是通用量化:它表示fromBase适用于所有T。因此,当您尝试将Base<Person>中的参数专门化为PersonMaster时,类型检查器会正确地抱怨fromBase的此实现不适用于所有T,仅适用于Person。重写方法的类型参数必须与声明的方法的类型参数匹配。

换句话说,T中声明的fromBase与封闭范围中的T完全不同class Master<T> extends Base<T> { static fromBase<U>(base: Base<U>) { /* ... */ } } 。它恰好影响了这个名字。如果两个类型参数具有不同的名称,则可能更容易理解:

T

在这种情况下,我怀疑您打算使用Master中的(严格T,而不是新鲜的(更高级别interface MasterFactory<T> { fromBase(base: Base<T>): Master<T> } class PersonMasterFactory implements MasterFactory<Person> { fromBase(base: Base<Person>): Master<Person> { /* ... */ } } let personMasterFactory = new PersonMasterFactory(); 。遗憾的是,正如您在评论中指出的那样,您无法使用静态方法来执行此操作,因为TypeScript不支持它。 (我无法找到任何关于语言设计师为什么做出这个决定的文档。我个人想不出任何好的理由,虽然我确定有一个。)所以你必须把你的方法转移到某个其他对象的实例方法:

PersonMaster.fromBase

通过此设计,可以转到personMasterFactory.fromBase的来电将转到var Season = [];

首先覆盖静态方法是一件非常奇怪的事情。方法覆盖是基于接收器的类型动态地调度调用,但是(概念上,至少)静态方法没有接收器。名称中的线索:动态调度静态方法没有意义!