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
Map Typescript Enum
提问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.Hello
is actually 1
at 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 type
statement 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 -> string
map.
您还会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-util
always 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.
现在您不需要任何映射函数并且它按预期工作,但是您必须为每个枚举创建单独的类似类(这应该不是问题,因为无论如何您都会这样做)。我现在能想到的唯一缺点是你不能迭代它的属性。但直到现在这对我来说都不是问题,我不需要它。您可以在需要时向类添加静态数组。