मैं टाइपस्क्रिप्ट में एनम को स्ट्रिंग करने के लिए कैसे परिवर्तित करूं?


311

मैंने टाइपस्क्रिप्ट में निम्नलिखित एनम को परिभाषित किया है:

enum Color{
    Red, Green
}

अब अपने फंक्शन में मैं एक स्ट्रिंग के रूप में रंग प्राप्त करता हूं। मैंने निम्नलिखित कोड आज़माया है:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum

मैं उस मान को एनम में कैसे बदल सकता हूं?

जवाबों:


430

TypeScript 0.9 में Enums स्ट्रिंग + नंबर आधारित हैं। आपको साधारण रूपांतरणों के लिए अभिकथन की आवश्यकता नहीं होनी चाहिए:

enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green];

इसे ऑनलाइन आज़माएं

मैंने अपनी ओएसएस पुस्तक में इस और अन्य एनुम पैटर्न के बारे में दस्तावेजीकरण किया है: https://basarat.gitbook.io/typescript/type-system/enums


111
इसके साथ काम नहीं करता है --noImplicitAny(वीएस अनियंत्रित "अंतर्निहित 'किसी भी प्रकार के" अनुमति दें ")। यह error TS7017: Index signature of object type implicitly has an 'any' type.मेरे लिए यह काम करता है: var color: Color = (<any>Color)[green];(संस्करण 1.4 के साथ परीक्षण किया गया)
वोज्टा

3
@Vojta ने सही कहा। वीएस 2012 में इसका काम नहीं कर रहा है। इसने एक रंग पर काम किया: लेकिन रंग = (<कोई> रंग) [हरा];
फैसल मक

3
यह यहां भी काम नहीं करता है, आधिकारिक दस्तावेज यह पुष्टि करता है कि: टाइपस्क्रिप्टlang.org/docs/handbook/release-notes/…
Pieter De Bie

26
यह सुनिश्चित करने के लिए उपयोग करें अगर --noImplicitAny var color : Color = Color[green as keyof typeof Color];
जोनास

2
@ Naxos84 मेरा उत्तर देखें stackoverflow.com/a/56076148/294242
जोनास

122

टाइपस्क्रिप्ट में 2.1 स्ट्रिंग कुंजियों का Enums दृढ़ता से टाइप किया गया है। keyof typeofउपलब्ध स्ट्रिंग कुंजी के बारे में जानकारी प्राप्त करने के लिए उपयोग किया जाता है ( 1 ):

enum Color{
    Red, Green
}

let typedColor: Color = Color.Green;
let typedColorString: keyof typeof Color = "Green";

// Error "Black is not assignable ..." (indexing using Color["Black"] will return undefined runtime)
typedColorString = "Black";

// Error "Type 'string' is not assignable ..." (indexing works runtime)
let letColorString = "Red";
typedColorString = letColorString;

// Works fine
typedColorString = "Red";

// Works fine
const constColorString = "Red";
typedColorString = constColorString

// Works fine (thanks @SergeyT)
let letColorString = "Red";
typedColorString = letColorString as keyof typeof Color;

typedColor = Color[typedColorString];

https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types


4
तो हम टाइपकास्ट का उपयोग कर सकते हैं:let s = "Green"; let typedColor = <keyof typeof Color> s;
सर्गेई

हां, और बदलने letके constबिना कास्टिंग के साथ काम करेंगे। इसे स्पष्ट करने के लिए अद्यतन उदाहरण। धन्यवाद @SergeyT
विक्टर

1
typedColorString = Color["Black"];अब लौटता हैerror TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'
डोमिनिक

2
एक पंक्ति का उत्तर:const color: Color = Color[colorString as keyof typeof Color];
19

38

यदि आप सुनिश्चित हैं कि इनपुट स्ट्रिंग का रंग एनम के साथ सटीक मेल है तो उपयोग करें:

const color: Color = (<any>Color)["Red"];

उस स्थिति में जहां इनपुट स्ट्रिंग Enum से मेल नहीं खाती है, का उपयोग करें:

const mayBeColor: Color | undefined = (<any>Color)["WrongInput"];
if (mayBeColor !== undefined){
     // TypeScript will understand that mayBeColor is of type Color here
}

खेल का मैदान


अगर हम टाइप enumकरने के लिए नहीं <any>आते हैं तो टाइपस्क्रिप्ट त्रुटि दिखाएगा:

तत्व का स्पष्ट रूप से 'कोई' प्रकार है क्योंकि सूचकांक अभिव्यक्ति प्रकार 'संख्या' का नहीं है।

इसका अर्थ है कि डिफ़ॉल्ट रूप से टाइपस्क्रिप्ट एनुम प्रकार संख्या इंडेक्स के साथ काम करता है, अर्थात let c = Color[0], जैसे स्ट्रिंग इंडेक्स के साथ नहीं let c = Color["string"]। यह अधिक सामान्य समस्या ऑब्जेक्ट स्ट्रिंग इंडेक्स के लिए Microsoft टीम द्वारा ज्ञात प्रतिबंध है ।


आप <keyof typeof Color> पर भी कास्ट कर सकते हैं। इसके अलावा "0" गलत इनपुट भी है लेकिन अपरिभाषित नहीं लौटेगा, इसलिए टाइपऑफ mayBeColor === 'नंबर' की जांच करें
क्वेंटिन 2

@ Quentin2 एक संख्यात्मक स्ट्रिंग के बारे में क्या? यानी typeof '0'होना चाहिएstring
पैट्रिक माइकल्सन

36
enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green as keyof typeof Color]; //Works with --noImplicitAny

यह उदाहरण --noImplicitAnyटाइपस्क्रिप्ट में काम करता है

स्रोत:
https://github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/advanced-types#index-types


मैं पता नहीं क्यों, लेकिन यह समाधान एक पर पर काम नहीं करता स्थिरांक enum (टाइपप्रति 3.8.3 का प्रयोग करके)
रॉबिन-हूडि

30

यह नोट मूल प्रश्न का नहीं, आधार के उत्तर से संबंधित है ।

मेरी अपनी परियोजना में एक अजीब मुद्दा था जहां संकलक इस कोड के बराबर का उपयोग करके "स्ट्रिंग को रंग में परिवर्तित नहीं कर सकता" के बराबर त्रुटि दे रहा था:

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.

मैंने पाया कि कंपाइलर टाइप का अनुमान भ्रमित हो रहा था और उसने सोचा कि यह colorIdएनम वैल्यू है और आईडी नहीं। समस्या को ठीक करने के लिए मुझे एक स्ट्रिंग के रूप में आईडी डालना था:

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.

मुझे यकीन नहीं है कि इस मुद्दे का कारण क्या है, लेकिन मैं इस नोट को यहां छोड़ दूंगा क्योंकि कोई भी उसी समस्या में चलता है जो मैंने किया था।


धन्यवाद! यह एक बहुत ही मूर्खतापूर्ण मुद्दा है और यह पता लगाना कठिन है कि समस्या क्या है। मैयबे टाइपस्क्रिप्ट को मसूड़ों को संभालने के बेहतर तरीके के साथ आने पर विचार करना चाहिए।
चिकनपेट

24

मुझे निम्नलिखित कोड का उपयोग करके काम करना पड़ा।

var green= "Green";
var color : Color= <Color>Color[green];

23

यदि आप अपने एनम को स्ट्रिंग मान प्रदान करते हैं, तो एक सीधी कास्ट ठीक काम करती है।

enum Color {
  Green = "Green",
  Red = "Red"
}

const color = "Green";
const colorEnum = color as Color;

1
बहुत आसान। अच्छा!
बर्नौली आईटी

1
यह भ्रामक हो सकता है क्योंकि यह अवैध रंगों से नहीं बचाता है। const colorEnum = "Blue" as Colorत्रुटि नहीं होगी, और आपको लगता colorEnumहै कि ठीक है छोड़ दिया जाएगा। लेकिन अगर आप console.logयह कर रहे थे , तो आप "ब्लू" देखेंगे। आर्ट्रू का जवाब अच्छा है, क्योंकि colorEnumहोगा undefined- और आप उसके बाद विशेष रूप से जांच कर सकते हैं।
एम फालंगा

20

यह देखते हुए कि आप टाइपस्क्रिप्ट का उपयोग करते हैं: ऊपर दिए गए कई समाधान काम नहीं कर सकते हैं या अत्यधिक जटिल हैं।

स्थिति : स्ट्रिंग्स एनम मान के समान नहीं होते हैं (आवरण भिन्न होते हैं)

enum Color {
  Green = "green",
  Red = "red"
}

महज प्रयोग करें:

const color = "green" as Color

15

मैं भी उसी कंपाइलर त्रुटि में भाग गया। Sly_cardinal के दृष्टिकोण की बस थोड़ी सी भिन्नता।

var color: Color = Color[<string>colorId];

एक अतिरिक्त के रूप में: यदि आपके पास जावास्क्रिप्ट टाइप द्वारा भरी गई एक टाइपरी एनम है, जो एनरम को स्ट्रिंग के रूप में क्रमबद्ध करती है (उदाहरण के लिए एंगुलरजेएस के माध्यम से एस्प वेब एपीआई) तो आप myProp.color = Color[<string><any>myProp.color] चीयर्स कर सकते हैं
विक्टर

1
यह मान्यताप्राप्त उत्तर होना चाहिए।
मिरोस्लाव पोपोव

9

यदि टाइपस्क्रिप्ट कंपाइलर जानता है कि चर का प्रकार स्ट्रिंग है तो यह काम करता है:

let colorName : string = "Green";
let color : Color = Color[colorName];

अन्यथा आपको इसे स्पष्ट रूप से एक स्ट्रिंग में बदलना चाहिए (संकलक चेतावनी से बचने के लिए):

let colorName : any = "Green";
let color : Color = Color["" + colorName];

रनटाइम पर दोनों समाधान काम करेंगे।


3
सिर्फ <string>colorNameइसके बजाय टाइपकास्ट का उपयोग क्यों नहीं करते "" + colorName?
सर्गेई

7

इस प्रश्न में बहुत सी मिली-जुली जानकारी है, इसलिए चलिए NickScript के गाइड में टाइप्स के साथ मॉडल में Enums का उपयोग करने के लिए टाइपस्क्रिप्ट 2.x + के लिए पूरे कार्यान्वयन को कवर करते हैं ।

यह मार्गदर्शिका निम्न के लिए है: जो लोग क्लाइंट-साइड कोड बना रहे हैं, जो सर्वर से ज्ञात स्ट्रिंग्स के एक सेट का उपयोग कर रहे हैं, जो क्लाइंट साइड पर Enum के रूप में आसानी से तैयार किया जाएगा।

दुश्मनी को परिभाषित करें

आइए एनम के साथ शुरू करते हैं। यह कुछ इस तरह दिखना चाहिए:

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}

नोट की दो बातें यहाँ:

  1. हम स्पष्ट रूप से इन्हें स्ट्रिंग-समर्थित एनम मामलों के रूप में घोषित कर रहे हैं, जो हमें कुछ अन्य असंबंधित संख्याओं के साथ, उन्हें स्ट्रिंग्स के साथ त्वरित करने की अनुमति देता है।

  2. हमने एक विकल्प जोड़ा है जो हमारे सर्वर मॉडल पर मौजूद हो सकता है या नहीं भी हो सकता है UNKNOWN:। यह undefinedआपके द्वारा पसंद किए जाने पर संभाला जा सकता है , लेकिन मैं | undefinedजब भी संभव हो तो हैंडलिंग को सरल बनाने वाले प्रकारों से बचना पसंद करता हूं ।

एक UNKNOWNमामला होने के बारे में महान बात यह है कि आप कोड के बारे में वास्तव में स्पष्ट हो सकते हैं और अज्ञात एनम मामलों के लिए शैलियों को उज्ज्वल लाल और ब्लिंक बना सकते हैं ताकि आप जानते हैं कि आप कुछ सही ढंग से नहीं संभाल रहे हैं।

एनम को पार्स करें

हो सकता है कि आप इस एनम का उपयोग किसी अन्य मॉडल में या अकेले ही कर रहे हों, लेकिन आप JSON या XML (ha) से स्ट्रिंग-वाई टाइप किए गए एनम को अपने जोर से टाइप किए गए समकक्ष में पार्स करने जा रहे हैं। जब दूसरे मॉडल में एम्बेडेड होता है, तो यह पार्सर क्लास कंस्ट्रक्टर में रहता है।

parseIssueType(typeString: string): IssueType {
  const type = IssueType[typeString];
  if (type === undefined) {
    return IssueType.UNKNOWN;
  }

  return type;
}

यदि एनम ठीक से पार्स है, तो यह उचित प्रकार के रूप में समाप्त हो जाएगा। अन्यथा, यह होगा undefinedऔर आप इसे रोक सकते हैं और अपना UNKNOWNमामला वापस कर सकते हैं । यदि आप undefinedअपने अज्ञात मामले के रूप में उपयोग करना पसंद करते हैं , तो आप किसी भी परिणाम के लिए प्रयास कर सकते हैं।

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

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN

6
दुर्भाग्य से, यह सही नहीं लगता है या, कम से कम, सामान्य नहीं है। यह काम करता है क्योंकि आपकी चाबियाँ उन्हें सौंपे गए तार के बराबर होती हैं। यदि वे मेरे मामले में पसंद करते हैं, तो अलग है, हालांकि, यह काम नहीं करता है। प्रलेखन के शब्दों में : "ध्यान रखें कि स्ट्रिंग एनम के सदस्यों को एक रिवर्स मैपिंग उत्पन्न नहीं होती है।" आपका कोड कुछ इस तरह संकलन करेगा IssueType["REPS"]="REPS"। यदि आपने अपनी REPS="reps"IssueType["REPS"]="reps"
दुश्मनी को

... हमेशा वापस लौटें IssueType.UNKNOWNक्योंकि repsआपकी Enum में कोई चाबी नहीं है । बहुत बुरा, मुझे अभी भी इसके लिए कोई काम करने वाला समाधान नहीं मिला क्योंकि मेरे तार में हाइफ़न होते हैं जो उन्हें चाबी के रूप में अनुपयोगी बनाते हैं।
altocumulus

अंत में, मैंने कंपाइलर को आश्वस्त करते हुए इस उत्तर में एक हल ढूंढा कि यह एक स्ट्रिंग एनम नहीं था। इस जानकारी को अपने स्वयं के उत्तर में संपादित करने के लायक हो सकता है।
15

6

मुझे यह जानने की जरूरत है कि एनम मूल्यों पर लूप कैसे किया जाता है (कई एनमों के क्रमपरिवर्तन का परीक्षण कर रहा था) और मुझे यह काम करने के लिए मिला:

export enum Environment {
    Prod = "http://asdf.com",
    Stage = "http://asdf1234.com",
    Test = "http://asdfasdf.example.com"
}

Object.keys(Environment).forEach((environmentKeyValue) => {
    const env = Environment[environmentKeyValue as keyof typeof Environment]
    // env is now equivalent to Environment.Prod, Environment.Stage, or Environment.Test
}

स्रोत: https://blog.mikeski.net/development/javascript/typescript-enums-to-from-string/


यह जवाब जनभावनापूर्ण है! इसे प्यार करना। विशेष रूप से जिस तरह से आप स्ट्रिंग से बाहर एक एनम बनाते हैं। यह बहुत ही टाइपिंग बचा सकता है जब आप एनम या अन्य मामलों का परीक्षण कर रहे हैं।
फ्लोरियन लेटेजब

हां, मैं जेस्ट के साथ इसका उपयोग eachकेवल एक विधि के साथ हर एक
एनम

6

मैं एक ऐसे उत्तर की तलाश में था जो एक enumसे प्राप्त कर सकता है string, लेकिन मेरे मामले में, enums मूल्यों में अलग-अलग स्ट्रिंग मान प्रतिपक्ष थे। ओपी के लिए एक सरल पहेली थी Color, लेकिन मेरे पास कुछ अलग था:

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}

जब आप Gender.CantTellएक "Can't tell"स्ट्रिंग के साथ हल करने का प्रयास करते हैं , तो यह undefinedमूल उत्तर के साथ लौटता है ।

एक और जवाब

मूल रूप से, मैं एक और जवाब के साथ आया, दृढ़ता से इस जवाब से प्रेरित :

export const stringToEnumValue = <ET, T>(enumObj: ET, str: string): T =>
  (enumObj as any)[Object.keys(enumObj).filter(k => (enumObj as any)[k] === str)[0]];

टिप्पणियाँ

  • हम पहले परिणाम को लेते हैं filter, मान लेते हैं कि ग्राहक एनम से एक वैध स्ट्रिंग पारित कर रहा है। यदि ऐसा नहीं है, undefinedतो वापस कर दिया जाएगा।
  • हम कलाकारों enumObjके लिए anyक्योंकि साथ टाइपप्रति 3.0+ (वर्तमान में टाइपप्रति 3.5 का प्रयोग करके), enumObjके रूप में हल हो गई है unknown

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

const cantTellStr = "Can't tell";

const cantTellEnumValue = stringToEnumValue<typeof Gender, Gender>(Gender, cantTellStr);
console.log(cantTellEnumValue); // Can't tell

नोट: और, जैसा कि किसी ने टिप्पणी में बताया है, मैं भी इसका उपयोग करना चाहता था noImplicitAny

अपडेट किया गया वर्ज़न

कोई कास्ट anyऔर उचित टाइपिंग के लिए नहीं।

export const stringToEnumValue = <T, K extends keyof T>(enumObj: T, value: string): T[keyof T] | undefined =>
  enumObj[Object.keys(enumObj).filter((k) => enumObj[k as K].toString() === value)[0] as keyof typeof enumObj];

इसके अलावा, अपडेट किए गए संस्करण में इसे कॉल करने का एक आसान तरीका है और यह अधिक पठनीय है:

stringToEnumValue(Gender, "Can't tell");

3

enum

enum MyEnum {
    First,
    Second,
    Three
}

नमूना उपयोग

const parsed = Parser.parseEnum('FiRsT', MyEnum);
// parsed = MyEnum.First 

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined

संवेदनशील संवेदनशील मामले को अनदेखा करें

class Parser {
    public static parseEnum<T>(value: string, enumType: T): T[keyof T] | undefined {
        if (!value) {
            return undefined;
        }

        for (const property in enumType) {
            const enumMember = enumType[property];
            if (typeof enumMember === 'string') {
                if (enumMember.toUpperCase() === value.toUpperCase()) {
                    const key = enumMember as string as keyof typeof enumType;
                    return enumType[key];
                }
            }
        }
        return undefined;
    }
}

जो कोई भी मेरे return enumType[property];जैसा Skills = "anyvalue"
एनम है उसे

@ neustart47 क्या आप सवाल पूछना चाहते हैं?
1950

यह सवाल नहीं है। मैंने अभी किसी भी व्यक्ति के लिए कुछ परिवर्तनों का उल्लेख किया है जो मेरे पास उसी मामले की खोज कर रहे हैं जो मेरे पास है। आपका उत्तर सही है।
neustart47

2

आपके द्वारा किए गए तरीके से बनाई गई एनमों को एक ऐसी वस्तु में संकलित किया जाता है जो आगे (name -> value)और रिवर्स (value -> name)मैपिंग दोनों को संग्रहीत करती है । जैसा कि हम इस क्रोम devtools स्क्रीनशॉट से देख सकते हैं:

यहां छवि विवरण दर्ज करें

यहाँ एक उदाहरण है कि दोहरी मैपिंग कैसे काम करती है और एक से दूसरे में कैसे डाली जाए:

enum Color{
    Red, Green
}
// To Number
var greenNr: number = Color['Green'];
console.log(greenNr); // logs 1

// To String
var greenString: string = Color[Color['Green']];  // or Color[Color[1]
console.log(greenString); // logs Green

// In your example

// recieve as Color.green instead of the string green
var green: string = Color[Color.Green];  

// obtain the enum number value which corresponds to the Color.green property
var color: Color = (<any>Color)[green];  

console.log(color); // logs 1

1

इसे इस्तेमाल करे

var रंग: रंग = (किसी भी रंग के रूप में) ["हरा];

यह 3.5.3 संस्करण के लिए ठीक काम करता है


0

अगर आप अपने enum की कार्यक्षमता को बढ़ाने के लिए नाम स्थान का उपयोग कर रहे हैं तो आप भी कुछ ऐसा कर सकते हैं

    enum Color {
        Red, Green
    }

    export namespace Color {
      export function getInstance(color: string) : Color {
        if(color == 'Red') {
          return Color.Red;
        } else if (color == 'Green') {
          return Color.Green;
        }
      }
    }

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

  Color.getInstance('Red');
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.