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

How do I define a class in Typescript that accepts an interface that has two fields for the same generic and guarantee they are the same type?

对于标题中令人困惑的措辞,我深表歉意,我很难为这个问题想出一行摘要。这是一个解释我正在尝试做的事情的例子:

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 的一个版本,它不仅包含两个 "animals",而且这两个动物是同一类型。

现在这段代码正确地验证了最后一行对 td.addPair 的调用接收到两种相同类型的动物(在本例中是鱼),但这只是因为我明确设置了 T 变为 Fish。有没有一种方法可以定义它,这样我就可以说 MatingPair.animalMatingPair.otherAnimal 都具有联合 Animal 中的类型值,而且它们的类型相同?

您可以通过重构 Animal 集合的定义来达到您的目标 class 有点像这样:

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 但不能同时使用,因为它们不兼容。