从继承自基类型的类列表返回类型为T的项 - Typescript

时间:2018-05-14 10:59:05

标签: javascript typescript

我有一个类(Foo),用于保存项目列表,项目列表全部继承自基本类型(IBar),此列表可以包含任意数量的这些项目。

我遇到的问题是我正在尝试在Foo上创建一个get方法,该方法将泛型类型限制为从IBar继承的类型。

我目前的接口和类是:

interface IBar {
  bar : string;
}

interface IFizz extends IBar {
  buzz : string;
}

class Foo {

  get<T extends IBar>() : T {
    var item = this.list[0];
    return item;
  }

  list : Array<IBar>;
}

使用代码我试图运行:

var foo = new Foo();
var item = foo.get<IFizz>();

我在上面知道列表是空的,但这更像是试图让Typescript编译器不显示错误。调用foo.get的行很好并且没有错误,问题是get方法本身。 我从上面得到的错误是&#34; Type&#39; IBar&#39;不能分配给&#39;&#39;&#34;&#34;。

如果以C#作为参考,上面的内容是可行的(我相信),欢迎任何书面例子来帮助我解决这个问题。

由于

2 个答案:

答案 0 :(得分:1)

以上代码也无法在C#中运行。两种语言都试图阻止您这样做,因为这不是类型安全的。请考虑以下代码:

class Foo {
    get<T extends IBar>() : T {
        var item = this.list[0];
        return item;
    }

    list : Array<IBar> = [ new OneClass() ];
}

var foo = new Foo();
var item = foo.get<AnotherClass>();

OneClassAnotherClass都实现IBar,但list[0]的类型为OneClass,但调用者请求AnotherClass的实例。因此,如果编译器允许您编写的代码,则会item键入AnotherClass,但会保留OneClass的实例,这可能会导致运行时错误。

就像在C#中一样,你可以强制使用typescript编译器来使用类型断言(或者类似于C#中的强制转换)来执行此操作。虽然您可以这样做,但您应该有另一种机制来确保数组中的项目实际上是T的正确类型:

class Foo {
    get<T extends IBar>() : T {
        var item = this.list[0];
        return item as T;
    }
    list : Array<IBar> = [];
}

var foo = new Foo();
var item = foo.get<IFizz>();

答案 1 :(得分:1)

您试图断言索引0处的项目是IFizz,而不仅仅是IBar;在Foo的声明中,静态无法保证,只有在运行时才能使用特定数据。虽然可以断言它(return item as T;),但这只是隐藏问题:当代码实际运行时,索引0处的项可能不是IFizz

如果列表包含IFizz,则应声明该列表。如果它将包含任何类型的IBar,则应声明它 ,并且为IFizz实例使用它的任何代码都有责任确保这是真的。< / p>

相反,Foo应该使用它将包含的IBar的实际类型进行参数化:

class Foo<T extends IBar> {

  get() : T {
    var item = this.list[0];
    return item;
  }

  list : Array<T>;
}

然后

var item = foo.get();