कैसे प्रोग्राम को एक एनुम प्रकार enumerate करने के लिए?


90

कहो मेरे पास टाइपस्क्रिप्ट है enum, MyEnumनिम्नानुसार है:

enum MyEnum {
    First,
    Second,
    Third
}

enumमानों की एक सरणी का निर्माण करने के लिए टाइपस्क्रिप्ट 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?

जवाबों:


192

यह उस एनम का जावास्क्रिप्ट आउटपुट है:

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

जो इस तरह से एक वस्तु है:

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

स्ट्रिंग मान के साथ Enum सदस्य

टाइपस्क्रिप्ट 2.4 में संभवत: स्ट्रिंग एनम सदस्य मानों के लिए एनमों की क्षमता शामिल है। तो यह संभव है कि एक एनम के साथ समाप्त हो।

enum MyEnum {
    First = "First",
    Second = 2,
    Other = "Second"
}

// compiles to
var MyEnum;
(function (MyEnum) {
    MyEnum["First"] = "First";
    MyEnum[MyEnum["Second"] = 2] = "Second";
    MyEnum["Other"] = "Second";
})(MyEnum || (MyEnum = {}));

सदस्य नाम प्राप्त करना

हम ऊपर दिए गए उदाहरण को देख सकते हैं कि यह पता लगाने की कोशिश की जाए कि एनम सदस्यों को कैसे प्राप्त करें:

{
    "2": "Second",
    "First": "First",
    "Second": 2,
    "Other": "Second"
}

यहाँ मैं क्या लेकर आया हूँ:

const e = MyEnum as any;
const names = Object.keys(e).filter(k => 
    typeof e[k] === "number"
    || e[k] === k
    || e[e[k]]?.toString() !== k
);

सदस्य मान

एक बार, हमारे पास नाम हैं, हम ऐसा करके मूल्य प्राप्त करने के लिए उन पर लूप कर सकते हैं:

const values = names.map(k => MyEnum[k]);

एक्सटेंशन क्लास

मुझे लगता है कि ऐसा करने का सबसे अच्छा तरीका अपने स्वयं के कार्यों (पूर्व EnumEx.getNames(MyEnum)) का निर्माण करना है। आप किसी एनम में फ़ंक्शन नहीं जोड़ सकते।

class EnumEx {
    private constructor() {
    }

    static getNamesAndValues(e: any) {
        return EnumEx.getNames(e).map(n => ({ name: n, value: e[n] as string | number }));
    }

    static getNames(e: any) {
        return Object.keys(e).filter(k => 
            typeof e[k] === "number"
            || e[k] === k
            || e[e[k]]?.toString() !== k
        );
    }

    static getValues(e: any) {
        return EnumEx.getNames(e).map(n => e[n] as string | number);
    }
}

उत्सुकता से (क्योंकि कई लोगों ने इस उत्तर को उखाड़ा है), मुझे टीएस प्लेग्राउंड में काम करने के लिए नहीं मिल सकता है: shorturl.me/jJ8G2t क्या मैं कुछ गलत कर रहा हूं?
पीटर

1
@Peter मैंने स्ट्रिंग एनम के बारे में जानकारी शामिल करने के लिए उत्तर अपडेट किया। इसके अलावा, आप एक for ofबयान का उपयोग करना चाहते हैंfor in
डेविड शेरेट 15

24

साथ टाइपप्रति> = 2.4 आप स्ट्रिंग enums परिभाषित कर सकते हैं:

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

जावास्क्रिप्ट 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"
}

इस प्रकार, स्ट्रिंग एनम के मामले में, चीजों को फ़िल्टर करने की आवश्यकता नहीं है, Object.keys(Color)और Object.values(Color)(*) पर्याप्त हैं:

const colorKeys = Object.keys(Color) as (keyof typeof 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
*/

टाइपस्क्रिप्ट खेल के मैदान पर ऑनलाइन उदाहरण देखें

(*) पुराने ब्राउज़रों के लिए आवश्यक पॉलीफ़िल, देखें https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values#Browser-compatibility


इसमें त्रुटि हैElement implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Color'. No index signature with a parameter of type 'string' was found on type 'typeof Color'.
जोनास

1
@ जोनास मैंने इसे एक कास्ट के साथ तय किया है:Object.keys(Color) as (keyof typeof Color)[]
tanguy_k

बहुत बहुत धन्यवाद!
जोनास

9

आप एनम के नाम और सूचकांक प्राप्त करने के लिए फ़ंक्शंस जोड़ सकते हैं:

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 किए गए फ़ंक्शन के माध्यम से उजागर करने के बजाय कॉन्स्ट्स को , लेकिन क्योंकि निर्यात किए गए सदस्य एनम के सदस्य हैं, इसलिए यह उन्हें कार्य के रूप में होने के लिए स्पष्ट रूप से स्पष्ट है ताकि वे वास्तविक एनम सदस्यों के साथ भ्रमित न हों।

यह अच्छा होगा यदि टाइपस्क्रिप्ट ने सभी एनमों के लिए स्वचालित रूप से ऐसा कुछ उत्पन्न किया।


7

टाइपस्क्रिप्ट (विचार: प्रतिबिंब) में RTTI (रनटाइम प्रकार की जानकारी) की कोई अवधारणा नहीं है इसलिए ऐसा करने के लिए, ट्रांसप्लड जावास्क्रिप्ट के ज्ञान की आवश्यकता होती है। इसलिए, टाइपस्क्रिप्ट 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";
}

तो, यह जावास्क्रिप्ट, जहां MyEnum.0 == "First"और में एक नियमित वस्तु के रूप में मॉडलिंग की जाती है MyEnum.First == 0। इसलिए, सभी एनुम नामों की गणना करने के लिए, आपको उन सभी गुणों को प्राप्त करने की आवश्यकता है जो ऑब्जेक्ट से संबंधित हैं और जो संख्याएँ भी नहीं हैं:

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

ठीक है, तो अब मैंने आपको बताया है कि यह कैसे करना है, मुझे आपको यह बताने की अनुमति है कि यह एक बुरा विचार है । आप एक प्रबंधित भाषा नहीं लिख रहे हैं, इसलिए आप इन आदतों को नहीं ला सकते। यह अभी भी सादा पुराना जावास्क्रिप्ट है। अगर मैं कुछ प्रकार की विकल्पों की सूची को आबाद करने के लिए जावास्क्रिप्ट में एक संरचना का उपयोग करना चाहता था, तो मैं एक सादे पुराने सरणी का उपयोग करूंगा। एक एनम यहाँ सही विकल्प नहीं है, जिसका उद्देश्य है। टाइपस्क्रिप्ट का लक्ष्य मुहावरेदार, सुंदर जावास्क्रिप्ट उत्पन्न करना है। इस तरह से enums का उपयोग करना इस लक्ष्य को संरक्षित नहीं करता है।


5

मैंने डेविड शेरेट द्वारा प्रस्तावित समाधान का उपयोग किया और एक npm लाइब्रेरी लिखी जिसका आप नाम उपयोग कर सकते हैं 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);

3

प्रविष्टियों की एक सूची प्राप्त करने के लिए एक-लाइनर (कुंजी-मूल्य ऑब्जेक्ट / जोड़े):

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

2
enum MyEnum {
    First, Second, Third, NUM_OF_ENUMS
}

for(int i = 0; i < MyEnum.NUM_OF_ENUMS; ++i) {
    // do whatever you need to do.
}

5
यह केवल तभी काम करता है जब आपका एनम किसी भी मान को परिभाषित नहीं करता है (यह अच्छी तरह से पैक और वृद्धिशील है)। उदाहरण के लिए Enum मान "First = 0x1000" या "PageNotFound = 404" हो सकते हैं। NUM_OF_ENUMS हमेशा सबसे बड़े परिभाषित मूल्य से एक बड़ा होगा, इसलिए मेरे उदाहरणों में 0x1001 या 405 है।
अकू

2

यदि आप स्ट्रिंग्स के मानों को अपने एनम के साथ जोड़ना चाहते हैं तो ये तरीके काम नहीं करते हैं। एक सामान्य कार्य करने के लिए आप यह कर सकते हैं:

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

यह कार्य करता है क्योंकि टाइपस्क्रिप्ट पहले चरण में कुंजी और दूसरे चरण में मान जोड़ देगा।

टाइपस्क्रिप्ट में यह है:

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

1

joe के उत्तर ने मुझे यह एहसास दिलाया कि अधिक जटिल परीक्षण करने की तुलना में पहले N संख्यात्मक कुंजियों पर भरोसा करना बहुत आसान है:

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

4
यह एक खतरनाक धारणा है क्योंकि शत्रुओं को सौंपे गए मूल्यों को परिभाषित करना संभव है और उन्हें वृद्धिशील और अच्छी तरह से पैक होने की आवश्यकता नहीं है। यह न असामान्य उदाहरण के लिए एक enum में बिट मास्क को देखने के लिए शायद यह है कि 400 से शुरू एचटीएमएल त्रुटि कोड की एक मेज है, या
अकु



0

एक Enum पर Iterating

इसके लिए स्ट्रिंग एनम्स का सबसे अच्छा उपयोग किया जाता है। यहाँ एक उदाहरण है:

// This is a string enum
enum MyEnum {
    First = 'First',
    Second = 'Second',
    Third = 'Third',
}

// An enum is a TS concept
// However his MyEnum compiles to JS object:
//  {
//   "First": "First",
//   "Second": "Second",
//   "Third": "Third"
// } 


// Therefore we can get the keys in the following manner:
const keysArray = Object.keys(MyEnum);

for (const key of keysArray) {
    console.log(key)
}
// [LOG]: "First" 
// [LOG]: "Second" 
// [LOG]: "Third" 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.