我有一个扩展另一个的接口。现在我试图将超级接口类型的变量放入需要子接口类型参数的函数中。这是不可能的,因为超接口类型变量缺少某些属性。
这有点难以解释,所以我创建了一个带有Animal
接口的示例,该接口由Horse
接口扩展:
interface Animal {
age:number;
//... 100 other things
}
interface Horse extends Animal {
speed:number;
}
现在我有一个带有一个私有函数(rideHorse
)的模块,它只接受Horse
作为参数。还有一个公共函数(rideAnimal
),接受以下所有Animal
:
module AnimalModule {
function rideHorse(horse:Horse) {
alert(horse.speed);
}
export function rideAnimal(animal:Animal) {
animal.speed = 10; // Error: Animal cannot have speed
rideHorse(animal); // Error: 'animal' needs speed
}
}
// Calling the rideAnimal function
var myAnimal:Animal = {
age: 10
};
AnimalModule.rideAnimal(myAnimal);
正如您所看到的那样,这不起作用,因为animal
的{{1}}参数没有rideAnimal
。所以我的问题是:如何将speed
投射到animal
并在Horse
函数内手动添加speed
,这样错误就会消失?
答案 0 :(得分:4)
您可以将Animal
投射到这样的Horse
。
function rideAnimal(animal:Animal) {
var horse = animal as Horse;
horse.speed = 10;
rideHorse(horse);
}
答案 1 :(得分:2)
是的,您可以使用user defined type guards来处理此类自定义类型评估:
interface Animal
{
age: number;
//... 100 other things
}
interface Horse extends Animal
{
speed: number;
}
module AnimalModule
{
function rideHorse(horse: Horse)
{
alert(horse.speed);
}
function isHorse(a: Animal): a is Horse
{
return "speed" in a;
}
export function rideAnimal(animal: Animal)
{
if (isHorse(animal))
{
animal.speed = 10; // Ok
rideHorse(animal); // Ok
} else
throw new Error("You can only ride horses")
}
}
如果Horse
和Animal
是课程,您可能刚刚完成if (animal instanceof Horse)
而不是使用自定义类型后卫isHorse
答案 2 :(得分:0)
你可以做任何你想做的事,因为打字稿最后只是javascript。但是你失去了静态打字的好处...... 例如,你可以写 (动物).speed = 12,但它打破了编译时检查...
从面向对象的角度来看,你不应该没有速度骑动物。
你应该添加一个中间界面“Irideable”扩展动物并由马继承。
答案 3 :(得分:0)
我希望你的rideAnimal功能看起来像
export function rideAnimal<T extends Animal>(animal:T) {
animal.speed = 10; // Error: Animal cannot have speed
if (animal instanceof Horse) {
rideHorse(animal as any as Horse); // Error: 'animal' needs speed
}
}
在使用抽象语法树时,这实际上是一种非常常见的模式,并且您将获得一个泛型节点的引用,并且需要确定它的实际类型。
一个完整的例子是:
class A {}
class B extends A {
doSomething() {}
}
function test(a:A) {
if (a instanceof B) {
a.doSomething();
}
}