我为标题中令人困惑的措辞道歉,我很难找到问题的一行摘要。这是一个例子来解释我正在尝试做什么:
interface Fish {
type: 'fish';
}
interface Dog {
type: 'dog';
}
type Animal = Fish | Dog;
interface MatingPair<T> {
animal: T;
otherAnimal: T;
}
class AnimalCollection<T> {
private pairs: T[] = [];
addPair<V extends T>(subject: V) {
this.pairs.push(subject);
}
}
let td = new AnimalCollection<MatingPair<Animal>>();
// Correctly generates error, dog is not a fish
td.addPair<MatingPair<Fish>>({
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
});
// Incorrectly lets dogs and fish be a mating pair
td.addPair({
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
});
我希望能够声明addPair
应该收到MatingPair
的版本,其中不仅包含两个“动物”,而且这两种动物的类型相同。
现在,此代码正确验证了对最后一行td.addPair
的调用是否正在接收两个相同类型的动物(在本例中为fish),但这只是因为我明确设置了{{1}成为T
。有没有办法来定义这个,我可以说Fish
&amp; MatingPair.animal
两者的值都是union Animal中的类型,但两者的类型是相同的吗?
答案 0 :(得分:3)
您可以通过重新调整Animal集合类的定义来达到目标:
interface Fish {
type: 'fish';
}
interface Dog {
type: 'dog';
}
type Animal = Fish | Dog;
interface MatingPair<T> {
animal: T;
otherAnimal: T;
}
class AnimalCollection<T>
{
private pairs: MatingPair<T>[] = [];
addPair<V extends T>(subject: MatingPair<V>)
{
this.pairs.push(subject);
}
}
let td = new AnimalCollection<Animal>();
// Correctly generates error, dog is not a fish
td.addPair<Fish>({
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
});
// Correctly generates error, dog is not a fish
td.addPair({
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
});
它不是你要求的100% - 但会解决问题。
一点点解释。基本上在你的样本中你试图这样做:
let a: MatingPair<Animal> = {
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
}
这是完全合法的,因为animal
和otherAnimal
都属于Animal
类型,只是不同的动物。
虽然我的细微变化使代码看起来更像这样:
let a: MatingPair<Dog> = {
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
}
这是错误的,因为鱼不是狗。
在真实的示例中,想法是相同的,而不是Dog
我要求V
是Animal
的后代。因此,Dog
或Fish
,但不是两者兼容,因为它们不兼容。