如何将枚举映射为指定类型?TypeScript映射类型疑问
用映射类型正确处理枚举与联合字面量的方案
我太懂这种挫败感了——本来想靠映射类型省事儿,结果要么输出不是预期的结构,要么只能硬写重复代码,完全违背了用映射类型的初衷!别着急,咱们一步步拆解问题,找到优雅的解决办法。
先说说你可能踩的坑
先假设你之前的写法大概是这样(以数字枚举为例):
enum Fruit { Apple, Banana } // 错误写法:得到的是 { 0: string; 1: string; },而不是预期的 { Apple: string; Banana: string; } type BadFruitMap = { [K in Fruit]: string }; // 或者另一种错误写法:包含了反向映射的键("0"、"1") type WorseFruitMap = { [K in keyof typeof Fruit]: string };
问题出在:
- 数字枚举会自动生成反向映射(比如
Fruit[0] = "Apple"),所以keyof typeof Fruit会同时包含枚举名称("Apple"、"Banana")和数字字符串("0"、"1")。 - 直接用
[K in Fruit]遍历的是枚举的值(数字0、1),而不是枚举的键名。
如果是字符串枚举,虽然没有反向映射,但如果你的目标是用枚举值作为键,写法不对也会出问题。
正确实现方案
1. 针对枚举:按需选择「键名映射」或「枚举值映射」
场景A:以枚举的键名作为新类型的键
比如想得到{ Apple: { label: string }, Banana: { label: string } }:
enum Fruit { Apple, Banana } // 先过滤掉反向映射的数字键,只保留枚举名称 type FruitKeys = Exclude<keyof typeof Fruit, `${number}`>; // 再用映射类型生成目标类型 type FruitMap = { [K in FruitKeys]: { label: string; value: typeof Fruit[K]; // 可以关联枚举对应的值 } };
场景B:以枚举的值作为新类型的键
如果想得到{ 0: { name: "Apple" }, 1: { name: "Banana" } },或者把数字值转成字符串键:
// 直接遍历枚举值,如需转字符串键用 as 断言 type FruitValueMap = { [K in Fruit as `${K}`]: { name: Extract<keyof typeof Fruit, `${typeof Fruit[K]}`>; // 反向关联枚举名称 } };
对于字符串枚举,因为没有反向映射,写法更简单:
enum Fruit { Apple = "apple", Banana = "banana" } // 以枚举键名为键 type FruitKeyMap = { [K in keyof typeof Fruit]: { value: typeof Fruit[K] } }; // 以枚举值为键 type FruitValueMap = { [K in Fruit]: { key: keyof typeof Fruit & { [P in keyof typeof Fruit]: typeof Fruit[P] extends K ? P : never }[keyof typeof Fruit] } };
2. 针对联合字面量:直接遍历联合类型即可
如果你用type Fruit = "apple" | "banana",之前的问题大概率是错误地用了keyof Fruit(因为keyof作用于字符串字面量得到的是字符索引、迭代器等,不是字面量本身)。正确写法是直接遍历联合类型:
type Fruit = "apple" | "banana"; // 完美得到预期的映射类型 type FruitMap = { [K in Fruit]: { category: "fruit"; name: K; } };
为什么你之前的替代写法违背初衷?
大概率是你为了避开映射类型的坑,直接手动写了每个键的类型,比如:
// 违背初衷的写法:重复代码 type FruitMap = { apple: { category: "fruit" }, banana: { category: "fruit" } };
而上面的方案完全复用了枚举/联合类型的定义,符合映射类型「减少重复、动态生成」的初衷。
内容的提问来源于stack exchange,提问作者NSjonas
相关产品推荐
相关产品推荐

