2017-08-02 62 views
0

我想扩展一个类并将其动态类型合并为特定类型(从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

fromBaseMaster声明是通用的:

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

这是全称量化:它说,fromBase应为所有T工作。因此,当您尝试将参数专用于PersonMaster时,类型检查器正确地抱怨fromBase的这种实现不适用于所有T s,仅针对Person。重写方法的类型参数必须与声明方法的类型参数相匹配。

换句话说,在fromBase中声明的T与封闭范围中的T完全不同。它恰好掩盖了这个名字。这可能是更容易理解,如果这两个类型的参数有不同的名称:

class Master<T> extends Base<T> { 
    static fromBase<U>(base: Base<U>) { /* ... */ } 
} 

在这种情况下,我怀疑你打算使用(刚性TMaster,而不是一个新鲜的(上位T。不幸的是,当你在你的评论中指出,你不能使用静态方法来做到这一点,因为TypeScript不支持它。 (我还没有找到任何关于语言设计师为什么做出这个决定的文档,我个人想不出有什么好的理由,但我确定有这个理由。)所以你必须将你的方法移到对其他对象的实例方法:

interface MasterFactory<T> { 
    fromBase(base: Base<T>): Master<T> 
} 
class PersonMasterFactory implements MasterFactory<Person> { 
    fromBase(base: Base<Person>): Master<Person> { /* ... */ } 
} 
let personMasterFactory = new PersonMasterFactory(); 

有了这个设计,要求其将去PersonMaster.fromBase会去personMasterFactory.fromBase

重写静态方法首先是一件很奇怪的事情。方法重写是基于接收方的类型动态调度调用,但是(至少在概念上)静态方法没有接收方。线索的名称:动态分配静态方法没有意义!

+0

谢谢,下次使用时我会考虑到这一点,但它会给我'静态成员不能引用类类型参数.'如果我没有在函数定义中指定'T',错误 – Akxe

+0

我没有知道关于静态成员。看起来像是TypeScript设计师的疏忽,尽管我确信它有一个很好的理由。无论如何,我认为你有一个设计问题:重写静态成员是一件很奇怪的事情。重写是一种固有的动态行为,所以如果某些东西需要被重载,你应该把它作为一个实例属性 - 换句话说,提取一个'MasterFactory'类 –

+0

我应该在typescript GitHub上写一个问题吗?为什么重写静态方法很奇怪,为什么使用工厂呢?并编辑你的答案,因为它不幸是不正确的。 – Akxe