TypeScript 接口向下转换
Posted
技术标签:
【中文标题】TypeScript 接口向下转换【英文标题】:TypeScript interface downcasting 【发布时间】:2016-08-17 00:37:56 【问题描述】:我有一个正在扩展另一个接口的接口。现在我试图将超接口类型的变量放入需要子接口类型参数的函数中。这是不可能的,因为超接口类型变量缺少某些属性。
这有点难以解释,所以我创建了一个带有Animal
接口的示例,该接口由Horse
接口扩展:
interface Animal
age:number;
//... 100 other things
interface Horse extends Animal
speed:number;
现在我有一个带有一个私有函数 (rideHorse
) 的模块,它只接受一个 Horse
作为参数。还有一个公共函数 (rideAnimal
),接受所有 Animal
s,如下所示:
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);
正如您所见,这不起作用,因为rideAnimal
的animal
参数没有speed
。所以我的问题是:如何将我的animal
转换为Horse
并在rideAnimal
函数中手动添加speed
,这样错误就会消失?
【问题讨论】:
我不明白,您在下面的 cmets 中写道,所有动物都可以被认为是可以骑乘的,因此它们都需要速度。那么为什么不在 IAnimal 中定义速度呢? @AlexAnimal
接口已经定义,无法更改,但我的问题不是这个。我只是想知道是否可以将超接口转换为子接口。
【参考方案1】:
你可以做任何你想做的事,因为 typescript 最终只是 javascript。但是你失去了静态类型的好处...... 例如,你可以写 (animal).speed = 12,但它会破坏编译时间检查...
从面向对象的角度来看,你不应该骑着没有速度的动物。
您应该添加一个中间接口“Irideable”扩展动物并由马继承。
【讨论】:
我知道在没有speed
的情况下不可能骑Animal
,这就是为什么我想将speed
添加到animal
内的每个animal
对象rideAnimal
。
你会骑蠕虫吗?你的问题没有意义。您仍然可以将您的动物投射到任何动物并为其添加速度属性。但这是丑陋的设计
我明白你的意思,但在我的情况下,你可以假设animal
是可以骑的,但只是缺少speed
属性。很抱歉我的例子没有准确地反映现实世界。【参考方案2】:
我希望你的 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();
【讨论】:
虽然在我的情况下每个Animal
都应该变成Horse
,那么这样的if 语句不是没有必要的吗?此外,这并不能消除错误。
更新了代码以使用泛型,希望能更健壮一点,但老实说,如果您正在寻找某些属性,您可能需要考虑结构类型。例如。仅当动物具有速度属性与动物所属的类别时才调用rideHorse 方法。【参考方案3】:
是的,您可以使用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
【讨论】:
【参考方案4】:您可以像这样将Animal
转换为Horse
。
function rideAnimal(animal:Animal)
var horse = animal as Horse;
horse.speed = 10;
rideHorse(horse);
【讨论】:
这似乎是实现我想要的最简单的解决方案。虽然现在如果不将speed
添加到horse
将不会出现警告,所以speed
可以是undefined
。但我想这是一个很小的代价。
如果您想要更安全,请使用转换函数toHorse
,它接受Animal
,将其转换为Horse
,并在添加speed
后返回。
或者添加条件检查来检查动物是马(否则抛出)。我认为这是最好的方法。以上是关于TypeScript 接口向下转换的主要内容,如果未能解决你的问题,请参考以下文章