Typescript -基于枚举键动态分配对象值

8wtpewkr  于 2023-01-27  发布在  TypeScript
关注(0)|答案(1)|浏览(133)

我已经把这个代码在TS操场太,点击这里,希望它有帮助。

基于枚举键动态分配对象值

我有这个enum Animals,我试图完成的是在interface iAnimals中获取每个动物key及其关联的接口值(如果有),如果没有,则使用interface iBaseAnimal作为默认值,因此在这种情况下,'lion'将获取iBaseAnimal作为接口,但'snail'键应获取与'parrot'相同的iSnail ...等等。
任何帮助都将不胜感激

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
}
fwzugrvs

fwzugrvs1#

这可能不是你想要的,但是一个可能的解决方案是切换你定义动物的位置,而不是在枚举中定义它们,而是在接口中定义它们:

// dict of animal name string -> interface
interface IAnimalsDict {
  shark: IShark;
  parrot: IParrot;
  snail: ISnail;
}

// A string literal type for animal names
type SAnimalName = keyof IAnimalsDict;

// util type to get animal interface by animal name
type AnimalFor<TAnimalName extends SAnimalName> = IAnimalsDict[TAnimalName];

以下是它的使用和测试方法:

// Testing SAnimalName
const animalName: SAnimalName = 'parrot';
// @ts-expect-error not a SAnimalName string.
const badAnimalName: SAnimalName = 'megatron';
// Testing IAnimalsDict usage.
const shark: IAnimalsDict['shark'] = {
  name: 'Arthur',
  gender: 'male',
  wild: true,
  max_gills: 1,
};
// @ts-expect-error missing max_gills, a required property of IShark.
const shark2: IAnimalsDict['shark'] = {
  name: 'Arthur',
  gender: 'male',
  wild: true,
};

// Usage in a function:
const addAnimal = <TAnimalName extends SAnimalName> (animalKey: TAnimalName, animal: AnimalFor<TAnimalName>) => {
  // ...
}
// Test
addAnimal('snail', {
  name: 'Jordan',
  // @ts-expect-error bad value for `gender` because ISnail requires `'hermaphrodite'`.
  gender: 'unisex',
  wild: true,
});
addAnimal('snail', {
  name: 'Jordan',
  gender: 'hermaphrodite',
  wild: true,
});

在TS操场上运行这个。
这将为您提供三个方面:

  • 动物名称与动物界面关联的单一位置:(IAnimalsDict)。
  • 检查动物名称的类型:(SAnimalNames)。
  • 一种通过名称获取接口的方便实用程序类型:(AnimalFor)。

还有一个附带的好处就是你不必使用枚举!))

相关问题