[英]Typescript - Enum key values as union types
我也把這段代碼放在了 TS playground 中,點擊這里,希望對你有幫助。
就像我在animals
object 中所做的那樣,使用key in
獲取密鑰作為enum ANIMALS values
,我找不到一種方法來做同樣的事情,但喜歡 function param animalKey
的聯合類型。 得到像'cat' | 'lion' | 'parrot' | 'shark' | 'snail'
'cat' | 'lion' | 'parrot' | 'shark' | 'snail'
'cat' | 'lion' | 'parrot' | 'shark' | 'snail'
。
任何幫助將非常感激
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
}
這是一個可能的解決方案:
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
}
如果您打算稍后添加/刪除動物類型,您可以按照以下方式改進此模式,這非常有用:
// 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.