如何在Typescript中定义一个类,该类接受一个接口,该接口具有相同泛型的两个字段并保证它们是相同的类型?

时间:2017-01-09 05:38:17

标签: typescript typescript-typings

我为标题中令人困惑的措辞道歉,我很难找到问题的一行摘要。这是一个例子来解释我正在尝试做什么:

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中的类型,但两者的类型是相同的吗?

1 个答案:

答案 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' }
}

这是完全合法的,因为animalotherAnimal都属于Animal类型,只是不同的动物。

虽然我的细微变化使代码看起来更像这样:

let a: MatingPair<Dog> = {
  animal: { type: 'dog' },
  otherAnimal: { type: 'fish' }
}

这是错误的,因为鱼不是狗。

在真实的示例中,想法是相同的,而不是Dog我要求VAnimal的后代。因此,DogFish,但不是两者兼容,因为它们不兼容。