प्रकार सरणी के लिए टाइपस्क्रिप्ट एनुम


110

मेरे पास एक एनम इस तरह परिभाषित है:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

हालाँकि, मैं चाहूंगा कि इसे हमारे एपीआई से एक वस्तु सरणी / सूची के रूप में दर्शाया जाए:

[{id: 1, name: 'Percentage'}, 
 {id: 2, name: 'Numeric Target'},
 {id: 3, name: 'Completed Tasks'},
 {id: 4, name: 'Average Milestone Progress'},
 {id: 5, name: 'Not Measured'}]

क्या ऐसा करने के लिए आसान और देशी तरीका है या क्या मुझे एक फ़ंक्शन का निर्माण करना है जो एनम को एक इंट और स्ट्रिंग दोनों में जोड़ता है, और ऑब्जेक्ट को एक सरणी में बनाता है?


Enums वास्तविक वस्तुएं हैं जो रनटाइम पर मौजूद हैं। तो आप मैपिंग को कुछ इस तरह से कर सकते हैं: GoalProgressMeasurements[GoalProgressMeasurements.Completed_Tasks]एनम नाम पाने के लिए। मुझे नहीं पता कि क्या मदद करता है।
दुलली

क्या आप "हमारे एपीआई से" एक बेहतर विवरण दे सकते हैं, शायद उपयोग का एक उदाहरण दे सकते हैं
गिल्मरन

जवाबों:


52

एक मुश्किल बिट यह है कि टाइपस्क्रिप्ट इम्यूलेटेड ऑब्जेक्ट में एनम को 'डबल' करेगा, इसलिए इसे कुंजी और मान दोनों से एक्सेस किया जा सकता है।

enum MyEnum {
    Part1 = 0,
    Part2 = 1
}

के रूप में उत्सर्जित किया जाएगा

{
   Part1: 0,
   Part2: 1,
   0: 'Part1',
   1: 'Part2'
}

इसलिए आपको मैपिंग से पहले ऑब्जेक्ट को फ़िल्टर करना चाहिए। तो @Diullei के समाधान का सही उत्तर है। यहाँ मेरा कार्यान्वयन है:

// Helper
const StringIsNumber = value => isNaN(Number(value)) === false;

// Turn enum into array
function ToArray(enumme) {
    return Object.keys(enumme)
        .filter(StringIsNumber)
        .map(key => enumme[key]);
}

इसे इस तरह उपयोग करें:

export enum GoalProgressMeasurements {
    Percentage,
    Numeric_Target,
    Completed_Tasks,
    Average_Milestone_Progress,
    Not_Measured
}

console.log(ToArray(GoalProgressMeasurements));

1
एमएमएम यदि तब enum MyEnum { Part1 = 0, Part2 = 1 }बदल जाता है { Part1: 0, Part2: 1, 0: 'Part1', 1: 'Part2' }, तो जब आप console.log(Object.values(MyEnum))केवल 0,1 प्रिंट करते हैं, तो क्यों ?
जुआन जोस रामिरेज़

@ JuanJoséRamírez तुम कहाँ देखते हो? मेरे लिए Object.values(MyEnum)मूल्यांकन करता है["Part1", "Part2", 0, 1]
user8363

मैंने सिर्फ console.log(Object.values(MyEnum))अपने कंपोनेंट में छपवाया । मैं कोणीय का उपयोग कर रहा हूँ, यकीन है कि अगर यह संबंधित नहीं है। मैं टाइपस्क्रिप्ट में अनुभव नहीं कर रहा हूँ
जुआन जोस रामिरेज़

विभिन्न टीएस संस्करणों के माध्यम से व्यवहार बदल सकता है?
जुआन जोस रामिरेज़

3
मैं जाँच कर रहा है डॉक्स typescriptlang.org/docs/handbook/release-notes/... और ऐसा लगता स्ट्रिंग enums एक अलग व्यवहार कर। वे एक रिवर्स मैपिंग उत्पन्न नहीं करते हैं। मेरे कोड में, मैं एक स्ट्रिंग एनम का उपयोग कर रहा था, इस उदाहरण में स्ट्रिंग नहीं।
जुआन जोस रामिरेज़

46

यदि आप ES8 का उपयोग कर रहे हैं

केवल इस मामले के लिए यह पूरी तरह से ठीक काम करेगा। यह आपको दिए गए एनम की वैल्यू एरे देगा ।

enum Colors {
  WHITE = 0,
  BLACK = 1,
  BLUE = 3
}

const colorValueArray = Object.values(Colors); //[ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]

आप मिल जाएगा colorValueArrayइस तरह [ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]। सभी कुंजी सरणी के पहले भाग में और दूसरी छमाही में सभी मान होंगे।

यहां तक ​​कि इस तरह की एनम ठीक काम करेगी

enum Operation {
    READ,
    WRITE,
    EXECUTE
}

लेकिन यह समाधान इस तरह से विषम दुश्मनी के लिए काम नहीं करेगा

enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = "YES",
}

9
ध्यान रखें कि इससे डुप्लिकेट निकलेंगे। प्रत्येक तत्व के लिए स्ट्रिंग मान और संख्यात्मक मान, यह एक प्रकार है (string | YourEnumType)[]जो वह नहीं है जो आप प्रत्येक मामले में चाहते हैं।
क्रिश्चियन आइविसेविच

क्या यह गारंटी है कि पहली छमाही में चाबियाँ होंगी और दूसरी छमाही में मान होंगे? कोई संदर्भ?
नीके सेप

1
Object.values()ES6 का हिस्सा नहीं है। यह ES2017 का हिस्सा है।
१०

ध्यान दें कि ES8 जैसी कोई चीज नहीं है; जैसा कि @atiyar कहते हैं, इसे ES2017 कहा जाता है।
हेरिटेज बंदर

37

Enums वास्तविक वस्तुएं हैं जो रनटाइम पर मौजूद हैं। तो आप मैपिंग को कुछ इस तरह से करने में सक्षम हैं:

let value = GoalProgressMeasurements.Not_Measured;
console.log(GoalProgressMeasurements[value]);
// => Not_Measured

उसके आधार पर आप निम्नलिखित कोड का उपयोग कर सकते हैं:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

let map: {id: number; name: string}[] = [];

for(var n in GoalProgressMeasurements) {
    if (typeof GoalProgressMeasurements[n] === 'number') {
        map.push({id: <any>GoalProgressMeasurements[n], name: n});
    }
}

console.log(map);

संदर्भ: https://www.typescriptlang.org/docs/handbook/enums.html


3
आपको डिफॉल्ट को = 2तब तक लिखने की आवश्यकता नहीं है = 5- जब तक कि कुछ भी = 1स्वचालित रूप से +1 नहीं हो जाता।
सेबिलासे

9
शायद आपको इसकी आवश्यकता न हो, लेकिन यह अधिक अभिव्यंजक है। जो इसे बेहतर IMHO बनाता है।
सुबलीमेसीम

5
सिर्फ एक नोट यह स्ट्रिंग वैल्यू एनम के लिए काम नहीं करता है
बशर अली लाबादी

21

आसान समाधान। आप अपने Enum को ऑब्जेक्ट्स की एक सरणी में बदलने के लिए निम्न फ़ंक्शन का उपयोग कर सकते हैं।

 buildGoalProgressMeasurementsArray(): Object[] {

    return Object.keys(GoalProgressMeasurements)
              .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
 }

यदि आपको उस अंडरस्कोर को उतारने की आवश्यकता है, तो हम regex का उपयोग इस प्रकार कर सकते हैं:

buildGoalProgressMeasurementsArray(): Object[] {

    return Object.keys(GoalProgressMeasurements)
              .map(key => ({ id: GoalProgressMeasurements[key], name: key.replace(/_/g, ' ') }))
 }

8
आपको टाइप संख्या की कुंजियों को फ़िल्टर करना चाहिए Object.keys(GoalProgressMeasurements) .filter(key => typeof GoalProgressMeasurements[key] === 'number') .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
साल्वाडोर रूबियो मार्टिनेज

13

मैं उपयोग करता हूं

Object.entries(GoalProgressMeasurement).filter(e => !isNaN(e[0]as any)).map(e => ({ name: e[1], id: e[0] }));

एक सरल 1 लाइन जो काम करती है।

यह 3 सरल चरणों में काम करता है
- कुंजियों और मूल्यों के संयोजन का उपयोग करता है Object.entries
- गैर-संख्या को फ़िल्टर करता है (चूंकि टाइपस्क्रिप्ट रिवर्स लुकअप के लिए मान उत्पन्न करता है)।
- फिर हम इसे उस ऐरे ऑब्जेक्ट पर मैप करते हैं, जिसे हम पसंद करते हैं।


IE के साथ फ्रंट-एंड के साथ संगत नहीं होना चाहिए (अर्थात समर्थन नहीं करना चाहिए एक महान उत्तर है ... लेकिन मुझे लगता है कि ग्राहक हैं)। होपिंग बबैल इसे ट्रांसपायर करता है, लेकिन अन्य तरीकों से चिपके रहता है क्योंकि मैंने इसे सत्यापित नहीं किया है
TamusJRoyce

स्ट्रिंग एनम आसान है, बस करोObject.values(GoalProgressMeasurement)
CMS

11

यह आपको एनम मानों की एक सरणी देगा:

 Object.values(myEnum);

@PauloQueiroz यह वृद्धि को स्वचालित रूप से शीर्ष पर जाएगा। धन्यवाद!
गौरव पंवार

क्योंकि यह सही परिणाम नहीं देता है, इस पर stackoverflow.com/a/57266281/3548345
वॉल्क्स

10
class EnumHelpers {

    static getNamesAndValues<T extends number>(e: any) {
        return EnumHelpers.getNames(e).map(n => ({ name: n, value: e[n] as T }));
    }

    static getNames(e: any) {
        return EnumHelpers.getObjValues(e).filter(v => typeof v === 'string') as string[];
    }

    static getValues<T extends number>(e: any) {
        return EnumHelpers.getObjValues(e).filter(v => typeof v === 'number') as T[];
    }

    static getSelectList<T extends number, U>(e: any, stringConverter: (arg: U) => string) {
        const selectList = new Map<T, string>();
        this.getValues(e).forEach(val => selectList.set(val as T, stringConverter(val as unknown as U)));
        return selectList;
    }

    static getSelectListAsArray<T extends number, U>(e: any, stringConverter: (arg: U) => string) {
        return Array.from(this.getSelectList(e, stringConverter), value => ({ value: value[0] as T, presentation: value[1] }));
    }

    private static getObjValues(e: any): (number | string)[] {
        return Object.keys(e).map(k => e[k]);
    }
}

1
इन सहायकों के लिए धन्यवाद। बहुत उपयोगी।
user906573 17

4

पहले हमें इस एनम के लिए कुंजियों की एक सरणी मिलती है। फिर, मानचित्र () फ़ंक्शन का उपयोग करके, हम डेटा को वांछित प्रारूप में परिवर्तित करते हैं। आईडी कुंजी से प्राप्त की जाती है, नाम उसी कुंजी द्वारा एनम से प्राप्त किया जाता है।

const converted = Object.keys(GoalProgressMeasurements).map(key => {
        return {
            id: GoalProgressMeasurements[key],
            name: key,
        };
    });

2
Stackoverflow में आपका स्वागत है। सवालों का जवाब देते समय, इसका एक अच्छा विचार यह समझाने के लिए कि आपका कोड स्निपेट क्या करता है। अधिक जानकारी के लिए, यहां देखें: उत्तर कैसे दें
Djensen


कृपया अपने उत्तर में कुछ स्पष्टीकरण या विवरण जोड़ने पर विचार करें। यद्यपि यह प्रश्न का उत्तर दे सकता है, बस एक कोड के टुकड़े को एक उत्तर के रूप में जोड़कर, ओपी या भविष्य के समुदाय के सदस्यों को समस्या या प्रस्तावित समाधान को समझने में मदद नहीं करता है।
मैक्सिम

3

मुझे उपरोक्त उत्तर पसंद नहीं आया क्योंकि उनमें से कोई भी सही प्रकार से स्ट्रिंग / नंबरों के मिश्रण को नहीं संभालता है जो टाइपस्क्रिप्ट एनम में मान हो सकते हैं।

निम्न फ़ंक्शन मानों के लिए कुंजियों का एक उचित मानचित्र देने के लिए टाइपस्क्रिप्ट एनम के शब्दार्थ का अनुसरण करता है। वहां से, वस्तुओं की एक सरणी या सिर्फ कुंजी या सिर्फ मूल्य प्राप्त करना तुच्छ है।

/**
 * Converts the given enum to a map of the keys to the values.
 * @param enumeration The enum to convert to a map.
 */
function enumToMap(enumeration: any): Map<string, string | number> {
  const map = new Map<string, string | number>();
  for (let key in enumeration) {
      //TypeScript does not allow enum keys to be numeric
      if (!isNaN(Number(key))) continue;

      const val = enumeration[key] as string | number;

      //TypeScript does not allow enum value to be null or undefined
      if (val !== undefined && val !== null)
          map.set(key, val);
  }

  return map;
}

उदाहरण उपयोग:

enum Dog {
    Rover = 1,
    Lassie = "Collie",
    Fido = 3,
    Cody = "Mutt",
}

let map = enumToMap(Dog); //Map of keys to values

lets objs = Array.from(map.entries()).map(m => ({id: m[1], name: m[0]})); //Objects as asked for in OP
let entries = Array.from(map.entries()); //Array of each entry
let keys = Array.from(map.keys()); //An array of keys
let values = Array.from(map.values()); //An array of values

मैं यह भी बताता हूँ कि ओपी पीछे की ओर सोच रहा है। एनम में "कुंजी" तकनीकी रूप से बाएं हाथ की तरफ है और मूल्य दाहिने हाथ की तरफ है। टाइपस्क्रिप्ट आपको आरएचएस पर मूल्यों को दोहराने की अनुमति देता है जितना आप चाहते हैं।


1

enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}
    
const array = []
    
for (const [key, value] of Object.entries(GoalProgressMeasurements)) {
    if (!Number.isNaN(Number(key))) {
        continue;
    }

    array.push({ id: value, name: key.replace('_', '') });
}

console.log(array);


कृपया अपना उत्तर हमेशा केवल कोड चिपकाने के बजाय संदर्भ में रखें। अधिक जानकारी के लिए यहां देखें ।
gehbiszumeis

1

एक सरल उपाय है, इसलिए जब आप दौड़ते हैं, तो आपको Object.keys(Enum)पहले स्लाइस मान में और दूसरा कुंजी में वैल्यू और कीज़ का एक एरियर देने वाला होता है, इसलिए हम दूसरा स्लाइस वापस क्यों नहीं करते हैं, नीचे दिया गया कोड मेरे लिए काम करता है। ।

enum Enum {
   ONE,
   TWO,
   THREE,
   FOUR,
   FIVE,
   SIX,
   SEVEN
}
const keys = Object.keys(Enum); 
console.log(keys.slice(keys.length / 2));

जिज्ञासु यह क्यों ठुकरा दिया गया था? मेरा भी यही विचार था। क्या चिंता यह होगी कि टाइपस्क्रिप्ट बदल जाएगा और अब उसी तरह से एनमोंस नहीं करेगा?
टोनी स्मिथ

1

यहां मैं सही टाइपिंग के साथ सरल फ़ंक्शन का उपयोग करता हूं

/**
 * Helper to produce an array of enum values.
 * @param enumeration Enumeration object.
 */
export function enumToArray<T, G extends keyof T = keyof T>(enumeration: T): T[G][] {
  // tslint:disable: comment-format

  // enum Colors {
  //   WHITE = 0,
  //   BLACK = 1,
  // }
  // Object.values(Colors) will produce ['WHITE', 'BLACK', 0, 1]

  // So, simply slice the second half
  const enumValues = Object.values(enumeration);
  return enumValues.slice(enumValues.length / 2, enumValues.length) as T[G][];
}

उपयोग उदाहरण:

enum Colors {
  Red = 1,
  Blue = 2,
}
enumToArray(Colors)

अच्छा है। धन्यवाद!!!
मौरिसियो कॉन्ट्रेरास

0

आप इस तरह से कर सकते हैं:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

export class GoalProgressMeasurement {
    constructor(public goalProgressMeasurement: GoalProgressMeasurements, public name: string) {
    }
}

export var goalProgressMeasurements: { [key: number]: GoalProgressMeasurement } = {
    1: new GoalProgressMeasurement(GoalProgressMeasurements.Percentage, "Percentage"),
    2: new GoalProgressMeasurement(GoalProgressMeasurements.Numeric_Target, "Numeric Target"),
    3: new GoalProgressMeasurement(GoalProgressMeasurements.Completed_Tasks, "Completed Tasks"),
    4: new GoalProgressMeasurement(GoalProgressMeasurements.Average_Milestone_Progress, "Average Milestone Progress"),
    5: new GoalProgressMeasurement(GoalProgressMeasurements.Not_Measured, "Not Measured"),
}

और आप इसे इस तरह से उपयोग कर सकते हैं:

var gpm: GoalProgressMeasurement = goalProgressMeasurements[GoalProgressMeasurements.Percentage];
var gpmName: string = gpm.name;

var myProgressId: number = 1; // the value can come out of drop down selected value or from back-end , so you can imagine the way of using
var gpm2: GoalProgressMeasurement = goalProgressMeasurements[myProgressId];
var gpmName: string = gpm.name;

आप GoalProgressMeasurement को उस ऑब्जेक्ट के अतिरिक्त गुणों के साथ बढ़ा सकते हैं, जिसकी आपको आवश्यकता है। मैं प्रत्येक अभिगम के लिए इस दृष्टिकोण का उपयोग कर रहा हूं जो एक वस्तु होनी चाहिए जिसमें अधिक मूल्य हो।


0

चूंकि स्ट्रिंग्स वैल्यू वाले एनम उन लोगों से भिन्न होते हैं जिनके पास नंबर वैल्यू होती है, इसलिए @Nn8363 सॉल्यूशन से नॉनटर्न्स को फ़िल्टर करना बेहतर होता है।

यहां बताया गया है कि कैसे आप एनम या तो स्ट्रिंग्स, मिश्रित संख्या से मान प्राप्त कर सकते हैं:

    //Helper
    export const StringIsNotNumber = value => isNaN(Number(value)) === true;
    
    // Turn enum into array
    export function enumToArray(enumme) {
      return Object.keys(enumme)
       .filter(StringIsNotNumber)
       .map(key => enumme[key]);
    }


0

मैं एक टाइपस्क्रिप्ट थ्रेड में आश्चर्यचकित हूं, किसी ने भी टाइप टाइप के साथ मान्य टाइपस्क्रिप्ट फ़ंक्शन का समर्थन नहीं किया है। यहां @ user8363 समाधान की विविधता है:

const isStringNumber = (value: string) => isNaN(Number(value)) === false;

function enumToArray<T extends {}>(givenEnum: T) {
  return (Object.keys(givenEnum).filter(isStringNumber) as (keyof T)[]).map(
    (key) => givenEnum[key]
  );
}

0

मुझे नहीं लगता कि आदेश की गारंटी दी जा सकती है, अन्यथा Object.entriesपरिणाम के दूसरे आधे हिस्से को काटना और वहां से नक्शा करना काफी आसान होगा।

उपरोक्त उत्तरों के साथ केवल (बहुत मामूली) मुद्दे हैं

  • स्ट्रिंग और संख्या के बीच अनावश्यक प्रकार का रूपांतरण होता है।
  • प्रविष्टियों को दो बार पुनरावृत्त किया जाता है जब एक एकल पुनरावृत्ति बस के रूप में स्वच्छ और प्रभावी होती है।
type StandardEnum = { [id: string]: number | string; [nu: number]: string;}

function enumToList<T extends StandardEnum> (enm: T) : { id: number; description: string }[] {
    return Object.entries(enm).reduce((accum, kv) => {
        if (typeof kv[1] === 'number') {
            accum.push({ id: kv[1], description: kv[0] })
        }
        return accum
    }, []) // if enum is huge, perhaps pre-allocate with new Array(entries.length / 2), however then push won't work, so tracking an index would also be required
}

0
function enumKeys(_enum) {
  const entries = Object.entries(_enum).filter(e => !isNaN(Number(e[0])));
  if (!entries.length) {
    // enum has string values so we can use Object.keys
    return Object.keys(_enum);
  }
  return entries.map(e => e[1]);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.