You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于TypeScript枚举创建映射并强制遗漏成员时报错?

问题

我需要做一个从ANIMAL_PLACE枚举到ANIMAL_TYPE枚举的映射对象,要求编译器在两种情况下报错:

  • 漏写了ANIMAL_PLACE里的任何成员
  • 漏用了ANIMAL_TYPE里的任何成员

现在的代码只能部分满足需求:

  • 自定义的AnimalPlaceToAnimalMapType既不检查ANIMAL_PLACE的遗漏,也不检查ANIMAL_TYPE的遗漏
  • 用Record<ANIMAL_PLACE, ANIMAL_TYPE[]>定义的对象,只会在漏写ANIMAL_PLACE成员时报错,管不了ANIMAL_TYPE的成员有没有全用上

代码示例:

export enum ANIMAL_TYPE {
    dog = "dog",
    cat = "cat",
    fish = "fish",
    foo = "foo"
}

export enum ANIMAL_PLACE {
        europe = 'europe',
        africa = 'africa',
        asia = "asia"
}

// 既不检测ANIMAL_PLACE遗漏,也不检测ANIMAL_TYPE遗漏
type AnimalPlaceToAnimalMapType = {
    [ANIMAL_PLACE.africa]: [ANIMAL_TYPE.cat, ANIMAL_TYPE.fish]
    [ANIMAL_PLACE.europe]: [ANIMAL_TYPE.dog]
}

// 只检测ANIMAL_PLACE成员遗漏
const AnimalPlaceToAnimalMapRecord: Record<ANIMAL_PLACE, ANIMAL_TYPE[]> = {
    [ANIMAL_PLACE.africa]: [ANIMAL_TYPE.cat, ANIMAL_TYPE.fish],
    [ANIMAL_PLACE.europe]: [ANIMAL_TYPE.dog],
};
解决方案

1. 同时检测两种遗漏情况

要同时管住ANIMAL_PLACE和ANIMAL_TYPE的遗漏,可以写一个辅助类型来校验所有ANIMAL_TYPE成员是否都被包含在映射里,再结合Record来约束ANIMAL_PLACE的完整性:

先写辅助类型:

// 校验所有ANIMAL_TYPE成员都被覆盖的辅助类型
type AllAnimalTypesCovered<T extends Record<ANIMAL_PLACE, ANIMAL_TYPE[]>> = 
  T[keyof T][number] extends infer AllUsedTypes
  ? ANIMAL_TYPE extends AllUsedTypes
    ? T
    : never
  : never;

然后用这个辅助类型约束最终的映射类型:

type AnimalPlaceToAnimalMap = AllAnimalTypesCovered<Record<ANIMAL_PLACE, ANIMAL_TYPE[]>>;

现在创建对象时,必须同时满足两个要求:

  • 所有ANIMAL_PLACE的成员都得写
  • 所有ANIMAL_TYPE的成员必须出现在至少一个数组里

比如正确的写法:

const AnimalPlaceToAnimalMap: AnimalPlaceToAnimalMap = {
  [ANIMAL_PLACE.africa]: [ANIMAL_TYPE.cat, ANIMAL_TYPE.fish],
  [ANIMAL_PLACE.europe]: [ANIMAL_TYPE.dog],
  [ANIMAL_PLACE.asia]: [ANIMAL_TYPE.foo] // 必须加foo,不然报错
};

漏写ANIMAL_PLACE.asia或者漏用ANIMAL_TYPE.foo,编译器都会直接报错。

2. 单独检测ANIMAL_TYPE遗漏(备选方案)

如果只需要确保ANIMAL_TYPE的成员都被用上,也可以用辅助函数来实现:

function createAnimalMap<T extends Record<ANIMAL_PLACE, ANIMAL_TYPE[]>>(
  map: T & AllAnimalTypesCovered<T>
): T {
  return map;
}

用这个函数创建对象:

// 漏了ANIMAL_TYPE.foo的话直接报错
const AnimalPlaceToAnimalMap = createAnimalMap({
  [ANIMAL_PLACE.africa]: [ANIMAL_TYPE.cat, ANIMAL_TYPE.fish],
  [ANIMAL_PLACE.europe]: [ANIMAL_TYPE.dog],
  [ANIMAL_PLACE.asia]: [ANIMAL_TYPE.foo]
});

这个方式同样能强制所有ANIMAL_TYPE成员被使用,同时Record的约束也会保证ANIMAL_PLACE的成员不遗漏。

内容的提问来源于stack exchange,提问作者four-eyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 22:04:54