地图打字稿枚举

Bra*_*ell 13 javascript enums typescript

我如何映射打字稿枚举?例如,使用字符串可以执行以下操作:

let arr = [ 'Hello', 'Goodbye' ];

arr.map(v => {
  if (v === 'Hello') {
    return ':)';
  } else if (v === 'Goodbye') {
    return ':(';
  }
); // [ ':)', ':(' ]
Run Code Online (Sandbox Code Playgroud)

当然,这不适用于枚举:

enum MyEnum { Hello, Goodbye };

MyEnum.map(v => {
  if (v === MyEnum.Hello) {
    return ':)';
  } else if (v === MyEnum.Goodbye) {
    return ':(';
  }
}); // does not work
Run Code Online (Sandbox Code Playgroud)

理想情况下,我想以一种通用的方式执行此操作,因此我可以简单地使用任何枚举,并通过map函数将其保留,同时保留类型信息.用法可能如下所示:

map(MyEnum, v => {
  if (v === MyEnum.Hello) {
    return ':)';
  } else if (v === MyEnum.Goodbye) {
    return ':(';
  }
}); // [ ':)', ':(' ]
Run Code Online (Sandbox Code Playgroud)

我一直在努力为我提供一个能够为我做这个功能的功能但是仍然存在让generics恰到好处的问题.

小智 76

要映射枚举,请执行以下操作:

(Object.keys(MyEnum) as Array<keyof typeof MyEnum>).map((key) => {})
Run Code Online (Sandbox Code Playgroud)

  • 添加到上面的内容中,如果您希望将键作为数组,请使用: ``` Object.keys(MyEnum).filter((el) =&gt; { return isNaN(Number(el)) }) ``` (3认同)
  • 使用以下命令更好地输入:`(Object.keys(MyEnum) as Array&lt; MyEnum &gt;` (3认同)

Ale*_*lop 16

Typescript 中的映射对于编写更少的代码来说非常强大。我最近经常使用键值枚举映射,并且会推荐它!这里有几个例子!

基本枚举用法

enum InlineStyle {
   "Bold",
   "Italic",
   "Underline"
}

type IS = keyof typeof InlineStyle

// Example of looping
(Object.keys(InlineStyle) as Array<IS>).forEach((key) => {
  // code here
})

// Example of calling a function
const styleInline = (style: IS) => {
  // code here
}
Run Code Online (Sandbox Code Playgroud)

枚举键值使用

enum ListStyle {
  "UL" = "List",
  "OL" = "Bullet points"
}

// Example of looping
Object.entries(ListStyle).forEach(([key, value]) => {
  // code here
})
Run Code Online (Sandbox Code Playgroud)

接口映射

enum InlineStyle {
   "Bold" = "isBold",
   "Italic" = "isItalic",
   "Underline" = "isUnderlined"
}

type InlineStyleType = Record<InlineStyle, boolean>

enum ListStyle {
  "UL",
  "OL"
}

type LS keyof typeof ListStyle

interface HTMLBlock extends InlineStyleType {
  // This has extended with
  // isBold: boolean
  // isItalic: boolean
  // isUnderlined: boolean

  listType: LS
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*ger 8

解决这个问题的功能非常简单。

// you can't use "enum" as a type, so use this.
type EnumType = { [s: number]: string };

function mapEnum (enumerable: EnumType, fn: Function): any[] {
    // get all the members of the enum
    let enumMembers: any[] = Object.keys(enumerable).map(key => enumerable[key]);

    // we are only interested in the numeric identifiers as these represent the values
    let enumValues: number[] = enumMembers.filter(v => typeof v === "number");

    // now map through the enum values
    return enumValues.map(m => fn(m));
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我们首先需要获取枚举的所有键(MyEnum.Hello实际上是1在运行时),然后只需映射它们,然后将函数传递给其他键。

使用它也很简单(尽管您更改了名称,但与您的示例相同):

enum MyEnum { Hello, Goodbye };

let results = mapEnum(MyEnum, v => {
  if (v === MyEnum.Hello) {
    return ':)';
  } else if (v === MyEnum.Goodbye) {
    return ':(';
  }
});

console.log(results); // [ ':)', ':(' ]
Run Code Online (Sandbox Code Playgroud)

我们只需要将枚举过滤为数字的原因是因为枚举的编译方式。

您的枚举实际上已编译为此:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["Hello"] = 0] = "Hello";
    MyEnum[MyEnum["Goodbye"] = 1] = "Goodbye";
})(MyEnum || (MyEnum = {}));
;
Run Code Online (Sandbox Code Playgroud)

但是,我们对它们不感兴趣,"Hello"或者"Goodbye"因为不能在运行时使用它们。


您还会type在函数之前注意到一个有趣的声明。这是因为您不能将参数键入为someParameter: enum,而需要将其显式声明为number -> string映射。


Jef*_*Lau 6

使用ts-enum-util( npm , github ),它很简单,类型安全(使用泛型),并且会为您跳过数字反向查找条目:

import { $enum } from "ts-enum-util";

enum MyEnum { Hello, Goodbye };

$enum(MyEnum).map(v => {
    if (v === MyEnum.Hello) {
        return ':)';
    } else if (v === MyEnum.Goodbye) {
        return ':(';
    }
}); // produces [':(', ':)']
Run Code Online (Sandbox Code Playgroud)

注意:ts-enum-util始终根据已排序的枚举键的顺序进行迭代,以保证所有环境中的顺序一致。Object.keys() 没有保证的顺序,因此不可能以跨平台保证的方式“按照定义的顺序”迭代枚举。(更新:新版本的 ts-enum-util 现在保留了定义枚举的原始顺序)

如果您使用的是字符串枚举,则将它与ts-string-visitor( npm , github )结合起来进行更通用的类型安全编译器检查,以确保您处理 map 函数中所有可能的枚举值:(更新:新版本的 ts-enum-util现在包括 ts-string-visitor 的功能,它现在也适用于数字枚举!)

import { $enum } from "ts-enum-util";
import { mapString } from "ts-string-visitor";

enum MyEnum { Hello = "HELLO", Goodbye = "GOODBYE" };

$enum(MyEnum).map(v => {
    // compiler error if you forget to handle a value, or if you
    // refactor the enum to have different values, etc.
    return mapString(v).with({
        [MyEnum.Hello]: ':)',
        [MyEnum.Goodby]: ':('
    });
}); // produces [':(', ':)']
Run Code Online (Sandbox Code Playgroud)