将枚举转换为自定义文字数组

Converting an enum to an array of custom literals

假设这样:

export enum Day {
  Monday = 111,
  Tuesday = 222,
  Wednesday = 333,
  Thursday = 444,
  Friday = 555,
  Saturday = 666,
  Sunday = 777,
}

Object.values(Day)
  .filter(v => typeof v === 'number') // or filter(Number)
  .map(numeric => console.log('numeric', numeric))
  // more code to come

我正在尝试从枚举中构建一个自定义对象数组,例如 { id: 111, label: 'Monday' },但我正在努力处理类型。

当鼠标悬停在 numeric 上时,我希望类型为 number,或者可能是 Day,但从未与 | string 联合,因为我正在过滤掉字符串就在它之前。

这是为什么?

关键在于 TypeScript 如何将 enum 代码转换为 JavaScript:

export var Day;
(function (Day) {
    Day[Day["Monday"] = 111] = "Monday";
    Day[Day["Tuesday"] = 222] = "Tuesday";
    Day[Day["Wednesday"] = 333] = "Wednesday";
    Day[Day["Thursday"] = 444] = "Thursday";
    Day[Day["Friday"] = 555] = "Friday";
    Day[Day["Saturday"] = 666] = "Saturday";
    Day[Day["Sunday"] = 777] = "Sunday";
})(Day || (Day = {}));

您可以通过查看 TypeScript Playground

中的 JS 输出自行验证这一点

基本上,它确保可以从任一方向查找枚举的值。什么是 Day.Monday?为什么是 111。但是 Day['111'] 是什么?啊,是'Monday'.

这是有效的,因为内部方括号中的表达式解析为分配的值。例如,Day["Monday"] = 111 解析为 111,因此 Day[Day["Monday"] = 111] = "Monday"; 本质上是 shorthand for:

Day["Monday"] = 111;
Day[111] = "Monday";

因此,当您将 Day 传递给 Object.values 时,您并不会像您预期的那样得到 [111, 222, 333, 444, 555, 666, 777]。相反,您得到 ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", 111, 222, 333, 444, 555, 666, 777]。 TypeScript 将其解释为 (string | Day)[].

类型

如果您希望打字稿推断 numeric 的实际类型,您可以在 map 之前使用类型保护,例如

function isNumber(v: unknown): v is number {
  return typeof v === 'number'
}
Object.values(Day)
  .filter(isNumber) // or filter(Number)
  .map(numeric => console.log('numeric', numeric)) // numeric is number