我有一个类(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#作为参考,上面的内容是可行的(我相信),欢迎任何书面例子来帮助我解决这个问题。
由于
答案 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>();
OneClass
和AnotherClass
都实现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();