如何根据泛型属性选择类型?
enum AnimalType {
DOG,
CAT,
FROG,
SNAKE,
}
const dog = {
type: AnimalType.DOG, // type property exists for all animals. other properties are vary for different animals
legs: 4,
}
const cat = {
type: AnimalType.CAT,
tail: 1,
}
const frog = {
type: AnimalType.FROG,
canSwim: true,
tail: 0,
}
const snake = {
type: AnimalType.SNAKE,
tail: 'looong',
age: 2,
}
type Animal<AnimalType> = typeof dog | typeof cat | typeof frog | typeof snake // how to rewrite this type definition?
如何根据AnimalType推断类型?例如Animal<AnimalType.DOG>
应等于 typeof dog
可以使用条件类型:
type Animal<T extends AnimalType> = T extends AnimalType.DOG ? typeof dog : T extends AnimalType.CAT ? typeof cat : T extends AnimalType.FROG ? typeof frog : T extends AnimalType.SNAKE ? typeof snake : unknown
但是它看起来太长并且完全无法阅读。希望有更好的解决办法
最佳答案
你可能打算这样做
const dog = {
type: AnimalType.DOG,
legs: 4,
}
类型为 {type: AnimalType.DOG, legs: number}
。但 TypeScript 推断出 AnimalType.DOG
的类型变得更宽enum类型AnimalType
而不是 literal type AnimalType.DOG
.
这意味着有人可以写 dog.type = AnimalType.CAT
,这不好。这也意味着typeof dog
没有可用于计算的信息 Animal<T>
.
要解决此问题,您需要告诉编译器 type
应该给出更具体的文字类型。通常的方法是使用 const
assertion关于有问题的字面意思。您可以对完整对象文字 {type: AnimalType.DOG, legs: 4} as const
执行此操作,如果您希望编译器强制执行 dog.legs
总是恰好 4
。但至少我们应该为 type
做到这一点属性(property)。产生这个:
const dog = { type: AnimalType.DOG as const, legs: 4 };
const cat = { type: AnimalType.CAT as const, tail: 1 };
const frog = { type: AnimalType.FROG as const, canSwim: true, tail: 0 };
const snake = { type: AnimalType.SNAKE as const, tail: 'looong', age: 2 };
现在是union type typeof dog | typeof cat | typeof frog | typeof snake
看起来像:
type SomeAnimal = typeof dog | typeof cat | typeof frog | typeof snake;
/* type SomeAnimal = {
type: AnimalType.DOG;
legs: number;
} | {
type: AnimalType.CAT;
tail: number;
} | {
type: AnimalType.FROG;
canSwim: boolean;
tail: number;
} | {
type: AnimalType.SNAKE;
tail: string;
age: number;
} */
这让我们可以实现 Animal
通过联合过滤 Extract
utility type :
type Animal<T extends AnimalType> =
Extract<SomeAnimal, { type: T }>;
让我们测试一下:
type Dog = Animal<AnimalType.DOG>;
/* type Dog = {
type: AnimalType.DOG;
legs: number;
} */
看起来不错。
关于typescript - 根据 typescript 中的通用属性选择类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77727851/