问题
我想定义一个养宠物的人,它是扩展Animal
的东西,而不仅仅是一个Animal
:
interface Person {
name: string
pet: extends Animal //I'm looking for something that would work here
}
我所尝试的
假设我们有这些接口:
interface Animal {
name: string
}
interface Fish extends Animal {
swim: () => void
}
interface Bird extends Animal {
fly: () => void
}
1.使用父类型
我知道我能做到:
interface Person {
name: string
pet: Animal // Not what I want, because it needs to be only things that extend Animal
}
但这会妨碍推理,因为如果pet
不是Fish
,它就应该是Bird
,但这样它也可以是普通的Animal
。
2.联合类型
为了只使用扩展Animal
的类型,我可以用联合类型自己挑选它们:
interface Person {
name: string
pet: Fish | Bird // Not what I want, because I would need to update it with new animals
}
但是如果我想创建更多的动物类型,我就必须每次更新Person
。
例如,如果我加上:
interface Mole extends Animal {
dig: () => void
}
我希望Person
自动接受Mole
作为宠物,而不通过将pet: Fish | Bird
更改为pet: Fish | Bird | Mole
来显式添加它。
总结
我正在寻找一种方法,它可以接受任何扩展Animal
的内容,但不能接受父Animal
本身,而不必在每次出现新动物时更新它。
备注
我不需要Animal
作为一个接口存在,但是如果它能保持一个接口就好了。
2条答案
按热度按时间k97glaaz1#
这就是泛型的用武之地:
泛型有点像“类型参数”,就像你可以为函数(
function(foo, bar) {}
)定义“值参数”一样,我们可以为大多数类型结构(包括函数function<A, B>(foo: A, bar: B) {}
,和你上面看到的接口)定义称为泛型的“类型参数”。当使用泛型时,我们可以通过使用
extends
关键字来对泛型应用约束。例如,function<A extends number>(value: A) {}
将与编写function(value: number) {}
非常相似。使用泛型的版本更强大,但也更冗长。在这个简单的function
示例中,使用泛型将是多余的。然而,在您的interface
情况下,使用泛型将是您所需要的。记住鸭子打字
由于typescript是鸭子类型的(如果它走路像鸭子,说话像鸭子,那么它就是鸭子),所以您可能会得到一些您需要注意的意外行为。
例如,你可以让一个人养一只普通的动物作为宠物:
或者你可以让一个人养一只宠物,它不“延伸”动物,但看起来像动物:
..说到这个,
Person
看起来像动物,所以你可以有一个人和一个人作为宠物:这些问题不是由泛型引起的,而是 typescript 如何工作的核心问题。
运动场
llycmphe2#
像这样的东西有用吗?