[英]Typescript - Enum key values as union types
i have put this code in the TS playground too, click here , hope it helps.
我也把这段代码放在了 TS playground 中,点击这里,希望对你有帮助。
Like i have done in the animals object using key in to get the key as the enum ANIMALS values i cannot find a way to do the same but like union types for the function param animalKey .
就像我在animals object 中所做的那样,使用key in获取密钥作为enum ANIMALS values ,我找不到一种方法来做同样的事情,但喜欢 function param animalKey的联合类型。 to get the something like 'cat' | 'lion' | 'parrot' | 'shark' | 'snail'
得到像'cat' | 'lion' | 'parrot' | 'shark' | 'snail' 'cat' | 'lion' | 'parrot' | 'shark' | 'snail' 'cat' | 'lion' | 'parrot' | 'shark' | 'snail' . ![]()
'cat' | 'lion' | 'parrot' | 'shark' | 'snail' 。
Any help would be much appreciated
任何帮助将非常感激
enum ANIMALS {
CAT = 'cat',
LION = 'lion',
PARROT = 'parrot',
SHARK = 'shark',
SNAIL = 'snail'
}
interface iBaseAnimal {
name: string,
gender: 'male' | 'female'
wild: boolean
}
interface iShark extends iBaseAnimal {
max_gills: number
}
interface iParrot extends iBaseAnimal {
wing: {
length: 120,
unit: 'cm'
}
}
// DONE Overwritting property when extending base props with Omit
interface iSnail extends Omit<iBaseAnimal, 'gender'> {
gender: 'hermaphrodite'
}
interface iAnimals {
animals: {
// DONE Enum values as key
// PENDING way to interpolate proper interface value base on the enum key
[key in ANIMALS]: iBaseAnimal
},
// PENDING way to get Enum values as union types (similar to [key in ANIMALS] but for function param)
getAnimal: (animalKey:'lion', options: any) => void
}
Here is a possible solution:
这是一个可能的解决方案:
enum AnimalsEn {
CAT = "cat",
LION = "lion",
PARROT = "parrot",
SHARK = "shark",
SNAIL = "snail"
}
interface iBaseAnimal {
name: string,
gender: "male" | "female"
wild: boolean
}
type AnimalsExtends = {
[AnimalsEn.SHARK]: {
max_gills: number
},
[AnimalsEn.PARROT]: {
wing: {
length: 120,
unit: "cm"
}
},
[AnimalsEn.SNAIL]: {
gender: "hermaphrodite"
},
}
// Utility to merge two Definition B object properties shadowing A object properties
type $Merge<TA, TB> = Omit<TA, keyof TB> & TB;
// Getting the Base+Extended type of an Animal
type iAnimal<A extends AnimalsEn> =
A extends keyof AnimalsExtends ?
$Merge<iBaseAnimal, AnimalsExtends[A]> :
iBaseAnimal;
interface iAnimals {
animals: {
// PENDING way to interpolate proper interface value base on the enum key
[key in AnimalsEn]: iAnimal<key> // just using utility to get the right Type
},
// Enum as a type ARE union of their posibles values
getAnimal: (animalKey: AnimalsEn, options: any) => void
}
You can improve this pattern as follow espacialy usefull if you plan to add/remove animal types later:
如果您打算稍后添加/删除动物类型,您可以按照以下方式改进此模式,这非常有用:
// a type for AnyAnimal
type AnyAnimal = { [key in AnimalsEn]: iAnimal<key> }[AnimalsEn];
// adding a type property on the finals interfaces
// this way you could easily discriminate animals by their type, refinement works very well with this
type iAnimal<A extends AnimalsEn> =
(A extends keyof AnimalsExtends ?
$Merge<iBaseAnimal, AnimalsExtends[A]> :
iBaseAnimal) & { type: A };
// you could use it very smoothly now :
export class NotExhaustiveError extends Error {
constructor (value: never) {
super(`Not allowed Value[${value}]`);
}
}
function doingSomethingWith(animal: AnyAnimal) {
// here animal is like
// {
// type: AnimalsEn,
// gender: "male" | "female" | "hermaphrodite";
// name: string,
// wild: boolean,
// }
const type = animal.type;
switch (type) {
case AnimalsEn.CAT: // here is a cat!
break;
case AnimalsEn.LION: // here is a lion!
break;
case AnimalsEn.PARROT: // here is a parrot!
break;
case AnimalsEn.SHARK: // here is a shark!
break;
case AnimalsEn.SNAIL: // here is a snail!
break;
default: // this will *throw* at *compile* time if you forgot to handle a case before
throw new NotExhaustiveError(type);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.