2016-12-23 73 views
4

我将如何映射打印稿枚举?例如,对于字符串你可以这样做:Map Typescript枚举

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

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

这当然,不枚举工作:

enum MyEnum { Hello, Goodbye }; 

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

理想情况下,我想这样做是一个广义的方式,使我可以简单地接受任何枚举,并通过地图函数,同时保留类型信息。用法可能是这个样子:

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

我一直在摆弄周围与得到,这是否对我来说是功能,但保留其获得的仿制药恰到好处的问题。

回答

2

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

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

正如你所看到的,我们首先需要获得所有枚举的键(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); // [ ':)', ':(' ] 

我们需要过滤的枚举是数字的原因仅仅是因为这样枚举被编译。

你枚举实际上是编译成这样:

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

然而,我们不感兴趣的"Hello""Goodbye"因为我们不能使用那些在运行时。


也将函数前右注意到一个有趣的type声明。这是因为您无法输入someParameter: enum的参数,因此您需要明确声明它为number -> string地图。

+0

这很好,让我成为一个可行的解决方案,但它在保存类型信息方面没有做到。添加一些泛型将非常有帮助。根据[this](http://stackoverflow.com/questions/30774874/enum-as-parameter-in-typescript),但是,它看起来像使用泛型与枚举是不完全可能与打字稿迄今。 –

+0

您需要哪种类型的信息,具体而言,以及在哪里? –

+0

这个函数签名是一个改进:'function mapEnum (enumerable:EnumType,fn:(v:any)=> T):T []'。不幸的是'v'仍然有一种类型。理想情况下,'v'的类型可以从可枚举类型推断出来。不幸的是,目前看起来这不是可能的。 (虽然我很想错!) –

0

我不会把它普通,但我用了很多次,可能这将是方便别人太:

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

现在,您不需要任何映射功能和它的作品却如预期你有为每个枚举创建单独的类(这不应该是一个问题,因为无论如何你都会这样做)。我现在唯一可以考虑的缺点是你无法迭代它的属性。但直到现在,这对我来说不是问题,我不需要它。你可以在你需要的时候向这个类添加一个静态数组。

0

随着ts-enum-utilnpmgithub),它很容易,类型安全(使用泛型),并采取跳过数字反向查找条目,你的护理:根据ts-enum-util总是迭代:

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

注意排序的枚举键的顺序以保证在所有环境中的顺序一致。目的。keys()没有保证的顺序,因此不可能按照跨平台保证的方式“按照它们定义的顺序”迭代枚举。

如果使用字符串枚举,然后结合起来ts-string-visitornpmgithub)甚至更通用的类型安全的编译器检查,以保证你处理你的地图功能的所有可能的枚举值:

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