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

如何将枚举映射为指定类型?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 };

问题出在:

  1. 数字枚举会自动生成反向映射(比如Fruit[0] = "Apple"),所以keyof typeof Fruit会同时包含枚举名称("Apple"、"Banana")和数字字符串("0"、"1")。
  2. 直接用[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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:24:30