Come enumerare in modo programmatico un tipo enum in TypeScript 0.9.5?

Supponiamo di avere un enum di TypeScript, MyEnum, come segue:

enum MyEnum { First, Second, Third } 

Quale sarebbe il modo migliore in TypeScript 0.9.5 per produrre un array di valori enum? Esempio:

 var choices: MyEnum[]; // or Array choices = MyEnum.GetValues(); // plans for this? choices = EnumEx.GetValues(MyEnum); // or, how to roll my own? 

Questo è l’output JavaScript di quell’enumerazione:

 var MyEnum; (function (MyEnum) { MyEnum[MyEnum["First"] = 0] = "First"; MyEnum[MyEnum["Second"] = 1] = "Second"; MyEnum[MyEnum["Third"] = 2] = "Third"; })(MyEnum || (MyEnum = {})); 

Qual è un object come questo:

 Object { 0: "First", 1: "Second", 2: "Third", First: 0, Second: 1, Third: 2 } 

Nomi dei membri

Per ottenere i nomi dei membri enum, possiamo filtrare le chiavi dell’object per quando il valore corrispondente è un numero. In questo modo verranno trovati i nomi con lo stesso valore:

 const names = Object.keys(MyEnum) .filter(k => typeof MyEnum[k] === "number") as string[]; 

Contiene: ["First", "Second", "Third"]

Valori membri

Mentre per ottenere i valori del membro enum, possiamo filtrare i valori dell’object di qualsiasi cosa che sia un numero:

 const values = Object.keys(MyEnum) .map(k => MyEnum[k]) .filter(v => typeof v === "number") as number[]; 

Contiene: [0, 1, 2]

Classe di estensione

Penso che il modo migliore per farlo sia creare le proprie funzioni (ad esempio EnumEx.getNames(MyEnum) ). Non è ansible aggiungere una funzione a un enum.

 class EnumEx { private constructor() { } static getNamesAndValues(e: any) { return EnumEx.getNames(e).map(n => ({ name: n, value: e[n] as T })); } static getNames(e: any) { return Object.keys(e).filter(k => typeof e[k] === "number") as string[]; } static getValues(e: any) { return Object.keys(e) .map(k => e[k]) .filter(v => typeof v === "number") as T[]; } } 

Con TypeScript> = 2.4 puoi definire enumerazioni stringa:

 enum Color { RED = 'Red', ORANGE = 'Orange', YELLOW = 'Yellow', GREEN = 'Green', BLUE = 'Blue', INDIGO = 'Indigo', VIOLET = 'Violet' } 

Uscita 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 = {})); 

Qual è un object come questo:

 const Color = { "RED": "Red", "ORANGE": "Orange", "YELLOW": "Yellow", "GREEN": "Green", "BLUE": "Blue", "INDIGO": "Indigo", "VIOLET": "Violet" } 

Pertanto, nel caso di enumerazioni di stringhe, non è necessario filtrare le cose, sono sufficienti Object.keys(Color) e 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 */ 

Vedi l’ esempio online sul parco giochi TypeScript

(*) Polyfill necessario per i vecchi browser, vedere https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values#Browser_compatibility

Non esiste un concetto di RTTI (informazioni sul tipo di runtime) in TypeScript (think: reflection), quindi per fare ciò è richiesta la conoscenza del codice JavaScript transpiled. Quindi, assumendo TypeScript 0.95:

 enum MyEnum { First, Second, Third } 

diventa:

 var MyEnum; (function(MyEnum) { MyEnum[MyEnum["First"] = 0] = "First"; MyEnum[MyEnum["Second"] = 1] = "Second"; MyEnum[MyEnum["Third"] = 2] = "Third"; } 

Quindi, questo è modellato come un object normale in javascript, dove MyEnum.0 == "First" e MyEnum.First == 0 . Quindi, per enumerare tutti i nomi enum, è necessario ottenere tutte le proprietà che appartengono all’object e che non sono anche numeri:

 for (var prop in MyEnum) { if (MyEnum.hasOwnProperty(prop) && (isNaN(parseInt(prop)))) { console.log("name: " + prop); } } 

Ok, ora ti ho detto come farlo, mi è permesso dirti che questa è una ctriggers idea . Non stai scrivendo una lingua gestita, quindi non puoi portare queste abitudini. È ancora semplicemente un vecchio JavaScript. Se volessi usare una struttura in JavaScript per compilare un qualche tipo di lista di scelte, userei un semplice vecchio array. Un enum non è la scelta giusta qui, gioco di parole. L’objective di TypeScript è generare un JavaScript idiomatico, piuttosto carino. Usare le enumerazioni in questo modo non preserva questo objective.

Puoi aggiungere funzioni per ottenere i nomi e gli indici dell’enum:

 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] 

Si noti che è ansible esportare solo i _names e _indices anziché esporli tramite una funzione esportata, ma poiché i membri esportati sono membri dell’enumerazione è probabilmente più chiaro avere loro le stesse funzioni in modo da non essere confusi con i membri effettivi dell’enumerazione.

Sarebbe bello se TypeScript generasse qualcosa di simile automaticamente per tutte le enumerazioni.

Ho usato la soluzione proposta da David Sherret e ho scritto una libreria npm che puoi usare enum-values

Git: enum-values

 // 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); 
 enum MyEnum { First, Second, Third, NUM_OF_ENUMS } for(int i = 0; i < MyEnum.NUM_OF_ENUMS; ++i) { // do whatever you need to do. } 

Se si desidera associare valori di stringhe al proprio enumer, questi metodi non funzionano. Per avere una funzione generica puoi fare:

 function listEnum(enumClass) { var values = []; for (var key in enumClass) { values.push(enum[key]); } values.length = values.length / 2; return values; } 

Funziona perché TypeScript aggiungerà le chiavi nel primo passaggio e i valori nel secondo passaggio.

In TypeScript è:

 var listEnums =  (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); 

la risposta di joe mi ha fatto capire che è molto più facile affidarsi ai primi N tasti numerici che effettuare test più complessi:

 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)) 

Un one-liner per ottenere un elenco di voci (oggetti / coppie valore-chiave):

 Object.keys(MyEnum).filter(a=>a.match(/^\D/)).map(name=>({name, value: MyEnum[name] as number}));