TypeScript如何生成包含枚举所有属性的穷尽唯一数组?
实现包含TypeScript枚举所有值的穷尽唯一数组
要实现一个返回包含枚举每个值恰好一次的对象数组(类型为Array<{ id: EnumValue, label: string }>),可以通过两种方式解决:自动生成(推荐)或手动编写时通过类型约束检查。
方案一:自动生成(简洁且无重复风险)
这种方式利用枚举的内置特性,从枚举值直接映射生成数组,天然保证每个枚举值只出现一次,同时通过类型约束确保所有枚举值都被覆盖。
代码示例
// 定义枚举 enum StepId { STEP_ONE = 'step-one-id', STEP_TWO = 'step-two-id', } // 定义枚举值与标签的映射,必须包含所有枚举值,否则编译报错 const stepLabels: Record<StepId, string> = { [StepId.STEP_ONE]: 'Step One', [StepId.STEP_TWO]: 'Step Two', }; // 生成目标数组的函数 function getStepArray(): Array<{ id: StepId; label: string }> { // Object.values(StepId)返回枚举的所有值,每个值仅出现一次 return Object.values(StepId).map(id => ({ id, label: stepLabels[id] })); } // 调用结果符合预期 getStepArray(); // 返回: // [ // { id: StepId.STEP_ONE, label: 'Step One' }, // { id: StepId.STEP_TWO, label: 'Step Two' } // ]
优势
- 穷尽性保障:
Record<StepId, string>类型强制stepLabels必须包含所有StepId的键,遗漏任何枚举值都会触发编译错误。 - 唯一性保障:
Object.values(StepId)会返回枚举的每个值一次,生成的数组自然不会出现重复id。 - 类型安全:返回类型自动推导为目标类型,无需额外手动标注。
方案二:手动编写数组时的类型约束
如果需要手动编写数组,可以通过自定义类型来检查穷尽性和唯一性,但类型逻辑相对复杂,适合短枚举场景。
代码示例
enum StepId { STEP_ONE = 'step-one-id', STEP_TWO = 'step-two-id', } // 工具类型:获取枚举的所有值的联合类型 type EnumValues<T> = T[keyof T]; // 工具类型:检查数组元素id是否唯一 type IsUnique<T extends readonly { id: any }[]> = T extends [infer First, ...infer Rest] ? First['id'] extends Rest[number]['id'] ? never // 存在重复,返回never触发报错 : IsUnique<Rest> : true; // 工具类型:检查数组是否包含所有枚举值且id唯一 type ExhaustiveUniqueArray<T extends string | number> = readonly { id: T; label: string }[] & (EnumValues<typeof T> extends (infer U)['id'] ? (IsUnique<U> extends true ? U : never) : never); // 手动编写数组,违反穷尽性或唯一性都会报错 const stepConfig: ExhaustiveUniqueArray<StepId> = [ { id: StepId.STEP_ONE, label: 'Step One' }, { id: StepId.STEP_TWO, label: 'Step Two' }, // 取消注释下面这行会触发编译错误(重复id) // { id: StepId.STEP_TWO, label: 'Step Two' }, // 遗漏任何枚举值也会触发编译错误 ];
说明
IsUnique递归检查数组中每个id是否与后续元素重复,存在重复时返回never,触发类型错误。ExhaustiveUniqueArray同时检查数组是否包含枚举的所有值,以及id是否唯一,不符合条件时都会报错。
内容的提问来源于stack exchange,提问作者tdc
相关产品推荐
相关产品推荐

