如何以编程方式枚举Typescript 0.9.5中的枚举types?
说我有一个TypeScript枚举,MyEnum,如下所示:
enum MyEnum { First, Second, Third }
在TypeScript 0.9.5中生成枚举值数组的最佳方法是什么? 例:
var choices: MyEnum[]; // or Array<MyEnum> choices = MyEnum.GetValues(); // plans for this? choices = EnumEx.GetValues(MyEnum); // or, how to roll my own?
这是该枚举的JavaScript输出:
var MyEnum; (function (MyEnum) { MyEnum[MyEnum["First"] = 0] = "First"; MyEnum[MyEnum["Second"] = 1] = "Second"; MyEnum[MyEnum["Third"] = 2] = "Third"; })(MyEnum || (MyEnum = {}));
这是一个这样的对象:
Object { 0: "First", 1: "Second", 2: "Third", First: 0, Second: 1, Third: 2 }
会员名称
要获得枚举成员名称,我们可以通过任何string来过滤对象的值:
const objValues = Object.keys(MyEnum).map(k => MyEnum[k]); const names = objValues.filter(v => typeof v === "string") as string[];
包含: ["First", "Second", "Third"]
会员价值
虽然要获取枚举成员值,我们可以通过任何数字来过滤对象的值:
const values = objValues.filter(v => typeof v === "number") as number[];
包含: [0, 1, 2]
扩展类
我认为最好的办法是创build自己的函数(例如EnumEx.getNames(MyEnum)
)。 您不能将一个函数添加到一个枚举。
class EnumEx { static getNamesAndValues<T extends number>(e: any) { return EnumEx.getNames(e).map(n => ({ name: n, value: e[n] as T })); } static getNames(e: any) { return EnumEx.getObjValues(e).filter(v => typeof v === "string") as string[]; } static getValues<T extends number>(e: any) { return EnumEx.getObjValues(e).filter(v => typeof v === "number") as T[]; } private static getObjValues(e: any): (number | string)[] { return Object.keys(e).map(k => e[k]); } }
打字稿中没有RTTI(运行时types信息)的概念(think:reflection,),所以为了做到这一点,需要知道传递的JavaScript。 所以,假设打字稿0.95:
enum MyEnum { First, Second, Third }
变为:
var MyEnum; (function(MyEnum) { MyEnum[MyEnum["First"] = 0] = "First"; MyEnum[MyEnum["Second"] = 1] = "Second"; MyEnum[MyEnum["Third"] = 2] = "Third"; }
所以,这是build模为一个常规的对象在JavaScript中,其中MyEnum.0 == "First"
和MyEnum.First == 0
。 所以,要枚举所有枚举名称,您需要获取属于该对象的所有属性,这些属性也不是数字:
for (var prop in MyEnum) { if (MyEnum.hasOwnProperty(prop) && (isNaN(parseInt(prop)))) { console.log("name: " + prop); } }
好吧,现在我已经告诉过你怎么做了,我可以告诉你这是个坏主意 。 你不是在写托pipe语言,所以你不能带来这些习惯。 它仍然只是普通的旧javascript。 如果我想在javascript中使用一个结构来填充某种select列表,我会使用一个普通的旧数组。 一个枚举在这里是不正确的select,双关意图。 打字稿的目标是生成惯用的,漂亮的JavaScript。 以这种方式使用枚举不保留这个目标。
您可以添加函数来获取枚举的名称和索引:
enum MyEnum { First, Second, Third } namespace MyEnum { function isIndex(key):boolean { const n = ~~Number(key); return String(n) === key && n >= 0; } const _names:string[] = Object .keys(MyEnum) .filter(key => !isIndex(key)); const _indices:number[] = Object .keys(MyEnum) .filter(key => isIndex(key)) .map(index => Number(index)); export function names():string[] { return _names; } export function indices():number[] { return _indices; } } console.log("MyEnum names:", MyEnum.names()); // Prints: MyEnum names: ["First", "Second", "Third"] console.log("MyEnum indices:", MyEnum.indices()); // Prints: MyEnum indices: [0, 1, 2]
请注意,您可以只导出_names
和_indices
而不是通过导出的函数公开它们,但是因为导出的成员是枚举的成员,所以将它们作为函数是非常明确的,所以它们不会与实际的枚举成员相混淆。
如果Typescript为所有的枚举自动生成这样的东西,那将会很好。
我使用了由David Sherret提出的解决scheme,并写了一个npm库,您可以使用名为enum-values
…
Git:枚举值
// Suppose we have an enum enum SomeEnum { VALUE1, VALUE2, VALUE3 } // names will be equal to: ['VALUE1', 'VALUE2', 'VALUE3'] var names = EnumValues.getNames(SomeEnum); // values will be equal to: [0, 1, 2] var values = EnumValues.getValues(SomeEnum);
请注意,对于TypeScript> = 2.4,您可以定义string枚举:
enum Color { RED = 'Red', ORANGE = 'Orange', YELLOW = 'Yellow', GREEN = 'Green', BLUE = 'Blue', INDIGO = 'Indigo', VIOLET = 'Violet' }
JavaScript ES5输出:
var Color; (function (Color) { Color["RED"] = "Red"; Color["ORANGE"] = "Orange"; Color["YELLOW"] = "Yellow"; Color["GREEN"] = "Green"; Color["BLUE"] = "Blue"; Color["INDIGO"] = "Indigo"; Color["VIOLET"] = "Violet"; })(Color || (Color = {}));
这是一个这样的对象:
const Color = { "RED": "Red", "ORANGE": "Orange", "YELLOW": "Yellow", "GREEN": "Green", "BLUE": "Blue", "INDIGO": "Indigo", "VIOLET": "Violet" }
因此,在string枚举的情况下,不需要过滤事物, Object.keys(Color)
和Object.values(Color)
(*)就足够了:
const colorKeys = Object.keys(Color); console.log('colorKeys =', colorKeys); // ["RED","ORANGE","YELLOW","GREEN","BLUE","INDIGO","VIOLET"] const colorValues = Object.values(Color); console.log('colorValues =', colorValues); // ["Red","Orange","Yellow","Green","Blue","Indigo","Violet"] colorKeys.map(colorKey => { console.log(`color key = ${colorKey}, value = ${Color[colorKey]}`); }); /* color key = RED, value = Red color key = ORANGE, value = Orange color key = YELLOW, value = Yellow color key = GREEN, value = Green color key = BLUE, value = Blue color key = INDIGO, value = Indigo color key = VIOLET, value = Violet */
请参阅TypeScript操场上的在线示例
(*)旧浏览器需要填充填充,请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values#Browser_compatibility
enum MyEnum { First, Second, Third, NUM_OF_ENUMS } for(int i = 0; i < MyEnum.NUM_OF_ENUMS; ++i) { // do whatever you need to do. }
joe的回答让我意识到依靠前N个数字键比更复杂的testing更容易:
function getEnumMembers(myEnum): string[] { let members = [] for(let i:number = 0; true; i++) { if(myEnum[i] === undefined) break members.push(myEnum[i]) } return members } enum Colors { Red, Green, Blue } console.log(getEnumMembers(myEnum))
如果您想将string值与您的枚举相关联,则这些方法不起作用。 要有一个通用的function,你可以做:
function listEnum(enumClass) { var values = []; for (var key in enumClass) { values.push(enum[key]); } values.length = values.length / 2; return values; }
这是有效的,因为Typescript将在第一步中添加键,在第二步中添加值。
在types中它是:
var listEnums = <T> (enumClass: any): T[]=> { var values: T[] = []; for (var key in enumClass) { values.push(enumClass[key]); } values.length = values.length / 2; return values; }; var myEnum: TYPE[] = listEnums<TYPE>(TYPE);
获取条目列表(键值对象/对)的一行代码:
Object.keys(MyEnum).filter(a=>a.match(/^\D/)).map(name=>({name, value: MyEnum[name] as number}));