我如何在 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.animal
和 MatingPair.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' }
}
这是完全合法的,因为 animal
和 otherAnimal
都是 Animal
类型,只是不同的动物。
而我的细微更改使代码看起来更像这样:
let a: MatingPair<Dog> = {
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
}
这是错误的,因为鱼不是狗。
在真实示例中,想法是相同的,它只是代替 Dog
,我在那里提出要求 V
是 Animal
的后代。所以 Dog
或 Fish
但不能同时使用,因为它们不兼容。
对于标题中令人困惑的措辞,我深表歉意,我很难为这个问题想出一行摘要。这是一个解释我正在尝试做的事情的例子:
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.animal
和 MatingPair.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' }
}
这是完全合法的,因为 animal
和 otherAnimal
都是 Animal
类型,只是不同的动物。
而我的细微更改使代码看起来更像这样:
let a: MatingPair<Dog> = {
animal: { type: 'dog' },
otherAnimal: { type: 'fish' }
}
这是错误的,因为鱼不是狗。
在真实示例中,想法是相同的,它只是代替 Dog
,我在那里提出要求 V
是 Animal
的后代。所以 Dog
或 Fish
但不能同时使用,因为它们不兼容。