解决失去对类型约束的支持的问题

时间:2014-04-11 03:55:37

标签: typescript

这是我在旧版本的TypeScript中所做的事情,我在C#中使用此方法,但它不适用于最新的1.0版TypeScript。

以下是有效的方法:

class Base<T extends Base<T>> {
    public children : Array<T>;

    doAction() {
        this.children[0].promise(); // used to work
    }

    promise() : T {
        return this; // used to work
    }
}

class Child extends Base<Child> {
    public myString: string;
}

new Child().promise().myString; // used to work

过去一切都很和谐。

现在在TypeScript 1.0中,我在Base<T extends Base<T>>定义上得到了这个错误:

  

类型参数的约束不能引用同一类型参数列表中的任何类型参数。

如何修复此示例类,而不需要在类之外进行任何强制转换或将任何内容转换为&#34;任何&#34;?也许这种模式应该改变?

3 个答案:

答案 0 :(得分:10)

此处不再允许您使用T

class Base<T extends Base<T>>
--------------------------^

您必须使您的班级非通用或使用:

class Base<T extends Base<any>>

给出的原因是为了简化编译器:

  

在我们不断努力简化语言的过程中,我们正在简化通用约束所需要的内容。

     

在类型检查,错误报告和设计复杂性方面增加的额外开销没有增加足够的额外表现力以使其值得1.0。我们可能会在未来的TypeScript版本中重新考虑这一点。

- Breaking Changes Wiki

答案 1 :(得分:6)

我接受了史蒂夫的答案,因为他建议使用Base<T extends Base<any>>,但我想保留代码更改的副本,以解决Stack Overflow上的问题:

class Base<T extends Base<any>> { // 1. Set as any
    children: Array<T>;

    doAction() {
        this.children[0].promise();
    }

    promise(): T {
        return <any> this; // 2. cast to any
    }
}

class Child extends Base<Child> {
    public myString: string;
}

new Child().promise().myString;

这需要对任何一个进行转换,但它不是那么糟糕,因为它只在基类中。此更改不会影响使用Child或Base类的任何内容,因此总体而言它是一个非常理想的替代方案。


更新:在TS 1.7+中,可以使用polymorphic this完成此操作:

class Base {
    children: Array<this>;

    doAction() {
        this.children[0].promise();
    }

    promise(): this {
        return this;
    }
}

class Child extends Base {
    public myString: string;
}

new Child().promise().myString;

答案 2 :(得分:0)

promise() : T { return this; }这是一个非常弱的假设,很容易被破解,因为在基类中定义的向下转换不适用于任何子类

例如,在您的情况下,如果有人定义class SuperChild extends Child {},那么promise()的{​​{1}}会给您SuperChild而不是Child

除此之外,您可以按照以下方式使其工作:

SuperChild