typescript 地图打字稿枚举

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41308123/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:07:11  来源:igfitidea点击:

Map Typescript Enum

javascripttypescriptenums

提问by Braden Snell

How would I map a typescript enum? For example, with strings you can do this:

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

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

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

This, of course, doesn't work with enums:

这当然不适用于枚举:

enum MyEnum { Hello, Goodbye };

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

Ideally, I'd like to do this in a generalized way so I can simply take any enum I have and put it through a map function while preserving type information. Usage might look something like this:

理想情况下,我想以通用的方式执行此操作,以便我可以简单地获取我拥有的任何枚举并将其放入 map 函数,同时保留类型信息。用法可能如下所示:

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

I've been fiddling around with getting a function that does this for me but keep having issues getting the generics just right.

我一直在摆弄一个为我做这件事的函数,但一直有问题让泛型恰到好处。

回答by James Monger

The function to solve this is quite simple.

解决这个问题的函数非常简单。

// 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));
}

As you can see, we first need to get all of the keys for the enum (MyEnum.Hellois actually 1at runtime) and then just map through those, passing the function on.

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

Using it is also simple (identical to your example, although I changed the name):

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

enum MyEnum { Hello, Goodbye };

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

console.log(results); // [ ':)', ':(' ]


The reason we need to filter the enum to be numbers only is because of the way enums are compiled.

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

Your enum is actually compiled to this:

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

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["Hello"] = 0] = "Hello";
    MyEnum[MyEnum["Goodbye"] = 1] = "Goodbye";
})(MyEnum || (MyEnum = {}));
;

However we are not interested in "Hello"or "Goodbye"as we can't use those at runtime.

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



You will also notice a funny typestatement right before the function. This is because you can't type a parameter as someParameter: enum, you need to explicitly state it as a number -> stringmap.

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

回答by Jeff Lau

With ts-enum-util(npm, github), it's easy, type-safe (uses generics), and takes care of skipping the numeric reverse lookup entries for you:

使用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 [':(', ':)']

NOTE: ts-enum-utilalways iterates based on the order of the sorted enum keys to guarantee consistent order in all environments. Object.keys() does not have a guaranteed order, so it's impossible to iterate enums "in the order they were defined" in a cross-platform guaranteed way. (update: new version of ts-enum-util now preserves the original order in which the enum was defined)

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

If you are using string enums, then combine it with ts-string-visitor(npm, github) for even more generic type-safe compiler checks to guarantee that you handle all possible enum values in your map function: (update: new version of ts-enum-util now includes functionality of ts-string-visitor, and it works on numeric enums now too!)

如果您使用的是字符串枚举,则将它与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 [':(', ':)']

回答by Manuel Fodor

I would not call it general but I use this many times and may it will be handy for others too:

我不会称之为通用,但我多次使用它,并且可能对其他人也很方便:

type TMyEnum = ':)'|':(';
class MyEnum {
    static Hello: TMyEnum = ':)';
    static Goodbye: TMyEnum = ':(';
}
console.log(MyEnum.Hello); // :)
console.log(MyEnum.Goodbye); // :(

Now you don't need any mapping function and it works as expected however you have to create separate similar class for every enum (which should not be a problem since you would do at anyway). The only drawback I can think now is that you can not iterate over it's properties. But until now it wasn't a problem for me I didn't need it. And you can add a static array to the class when you need it.

现在您不需要任何映射函数并且它按预期工作,但是您必须为每个枚举创建单独的类似类(这应该不是问题,因为无论如何您都会这样做)。我现在能想到的唯一缺点是你不能迭代它的属性。但直到现在这对我来说都不是问题,我不需要它。您可以在需要时向类添加静态数组。