प्रस्तावना: Stack Overflow पर शाश्वत प्रश्न
\n\nक्या आपने कभी सोचा है कि TypeScript पर अनुभवी डेवलपर्स enum के मानों के नाम कैसे प्राप्त करते हैं? यदि आपने Stack Overflow पर देखा है, तो आपने निश्चित रूप से हज़ारों व्यूज़ वाला एक प्रश्न देखा होगा: "How to get names of enum entries?"। इसमें मुश्किल क्या है, ऐसा लगता है? लेकिन व्यवहार में, कई नौसिखिए (और केवल वे ही नहीं) इस बिंदु पर फंस जाते हैं।
इस लेख में, हम केवल तैयार उत्तर नहीं देंगे। हम TypeScript के हुड के नीचे जाएंगे और समझेंगे कि enum वास्तव में कैसे काम करते हैं, कंपाइलर उन्हें JavaScript में कैसे बदलता है, और नाम प्राप्त करने के कुछ तरीके अप्रत्याशित बग क्यों पैदा कर सकते हैं। तैयार हैं? चलिए शुरू करते हैं!
TypeScript में enum क्या है और उनके नामों की आवश्यकता क्यों है?
\n\nEnum (गणना) नामित स्थिरांकों का एक सेट निर्दिष्ट करने का एक सुविधाजनक तरीका है। TypeScript में, वे संख्यात्मक (डिफ़ॉल्ट रूप से) और स्ट्रिंग हो सकते हैं। लेकिन यदि आपको किसी विशिष्ट मान का नाम प्राप्त करने की आवश्यकता हो तो क्या करें? उदाहरण के लिए, आपको API से स्टेटस कोड 403 मिला, और आप उपयोगकर्ता को एक समझने योग्य संदेश "Forbidden" दिखाना चाहते हैं।
enum HttpStatus {\n OK = 200,\n NotFound = 404,\n Forbidden = 403\n}\n\n// हमारा कार्य: मान 403 से नाम "Forbidden" प्राप्त करना\n\n\nऐसा लगता है कि TypeScript को इसके लिए एक अंतर्निहित विधि प्रदान करनी चाहिए। लेकिन ऐसा नहीं है। हमें अपना तर्क लिखना होगा। और यहीं से सबसे दिलचस्प शुरुआत होती है।
\n\nसीधा समाधान: Object.keys और Object.values
\n\nसबसे स्पष्ट तरीका Object.keys() या Object.values() विधियों का उपयोग करना है। कई नौसिखिए कुछ इस तरह लिखते हैं:
function getEnumName(enumObj: any, value: number): string | undefined {\n const keys = Object.keys(enumObj);\n return keys.find(key => enumObj[key] === value);\n}\n\nconsole.log(getEnumName(HttpStatus, 403)); // "Forbidden" — काम करता है!\n\n\nतार्किक लगता है? हाँ। लेकिन यदि आप इस कोड को संख्यात्मक enum पर आज़माते हैं, तो आपको एक आश्चर्य का सामना करना पड़ेगा। आइए देखें कि हमारा HttpStatus किसमें कंपाइल होता है।
हुड के नीचे: संख्यात्मक enum का कंपाइलेशन
\n\nजब TypeScript संख्यात्मक enum को कंपाइल करता है, तो यह रिवर्स मैपिंग (reverse mapping) के साथ एक ऑब्जेक्ट बनाता है। कंपाइल किया गया JavaScript इस तरह दिखता है:
\n\nvar HttpStatus;\n(function (HttpStatus) {\n HttpStatus[HttpStatus["OK"] = 200] = "OK";\n HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound";\n HttpStatus[HttpStatus["Forbidden"] = 403] = "Forbidden";\n})(HttpStatus || (HttpStatus = {}));\n\n// अंत में, HttpStatus ऑब्जेक्ट इस तरह दिखता है:\n// { \n// "200": "OK", \n// "404": "NotFound", \n// "403": "Forbidden", \n// "OK": 200, \n// "NotFound": 404, \n// "Forbidden": 403 \n// }\n\n\nचाल देखी? कंपाइलर संख्या-कुंजियाँ और स्ट्रिंग-कुंजियाँ दोनों जोड़ता है। इसलिए, Object.keys(HttpStatus) केवल ["OK", "NotFound", "Forbidden"] ही नहीं, बल्कि ["200", "404", "403"] भी लौटाएगा। यह हमारे सरल समाधान के तर्क को तोड़ देता है!
इससे बचने के लिए, संख्यात्मक कुंजियों को फ़िल्टर करना होगा:
\n\nfunction getEnumNameSafe(enumObj: any, value: number): string | undefined {\n const keys = Object.keys(enumObj).filter(key => isNaN(Number(key)));\n return keys.find(key => enumObj[key] === value);\n}\n\n\nलेकिन ऐसा कोड टेढ़ा लगता है। क्या कोई बेहतर तरीका है?
\n\nस्ट्रिंग enum: एक अलग कहानी
\n\nयदि आप स्ट्रिंग enum का उपयोग करते हैं, तो रिवर्स मैपिंग नहीं बनाई जाती है। यह कार्य को सरल बनाता है:
\n\nenum Direction {\n Up = "UP",\n Down = "DOWN",\n Left = "LEFT",\n Right = "RIGHT"\n}\n\n// Object.keys(Direction) केवल ["Up", "Down", "Left", "Right"] लौटाएगा — एकदम सही!\n\n\nलेकिन क्या होगा यदि आपको मान से नाम प्राप्त करने की आवश्यकता है? वही Object.keys पूरी तरह से काम करता है:
function getStringEn