TypeScript में रिफ्लेक्शन और इंट्रोस्पेक्शन: कोड स्वयं को कैसे देखता है
\n\nएक ऐसे प्रोग्राम की कल्पना करें जो रनटाइम में स्वयं का विश्लेषण करने में सक्षम हो। वह जान सकता है कि उसके वेरिएबल्स के कौन से प्रकार हैं, ऑब्जेक्ट्स में कौन से गुण हैं, और इस जानकारी के आधार पर निर्णय भी ले सकता है। जादू जैसा लगता है? वास्तव में यह रिफ्लेक्शन और इंट्रोस्पेक्शन है — मेटाप्रोग्रामिंग की शक्तिशाली तकनीकें, जो TypeScript में भी उपलब्ध हैं।
\n\nइस लेख में हम समझेंगे कि रिफ्लेक्शन, इंट्रोस्पेक्शन से कैसे भिन्न है, TypeScript में इनका उपयोग कैसे करें, और वास्तविक प्रोजेक्ट्स में यह क्यों उपयोगी हो सकता है। कोई उबाऊ सिद्धांत नहीं — केवल लाइव कोड और व्यावहारिक उदाहरण।
\n\nइंट्रोस्पेक्शन और रिफ्लेक्शन क्या हैं?
\n\nचलिए तुरंत स्पष्ट करते हैं। प्रोग्रामिंग में इन शब्दों को अक्सर भ्रमित किया जाता है, लेकिन अंतर है:
\n\n- \n
- इंट्रोस्पेक्शन — यह प्रोग्राम की अपनी संरचना का अवलोकन करने की क्षमता है। आप जान सकते हैं कि किसी ऑब्जेक्ट में कौन से गुण हैं, उसका प्रकार क्या है, लेकिन आप उन्हें बदल नहीं सकते। \n
- रिफ्लेक्शन — यह अधिक उन्नत स्तर है: प्रोग्राम न केवल स्वयं को देखता है, बल्कि रनटाइम में अपने व्यवहार को बदलता भी है। उदाहरण के लिए, गतिशील रूप से मेथड्स को कॉल करना या क्लासेस के नए इंस्टेंस बनाना। \n
JavaScript में, जिस पर TypeScript आधारित है, रिफ्लेक्शन Reflect और Proxy के माध्यम से कार्यान्वित किया जाता है। लेकिन TypeScript अपनी एक परत जोड़ता है — स्टैटिक टाइपिंग, जो कंपाइलेशन पर आंशिक रूप से 'गायब' हो जाती है। यहीं से सबसे दिलचस्प शुरुआत होती है।
प्रकारों का इंट्रोस्पेक्शन: type guards और typeof
\n\nकोड के अंदर झाँकने का सबसे सरल तरीका type guards का उपयोग करना है। ये ऐसी संरचनाएँ हैं जो रनटाइम में डेटा प्रकार की जाँच करती हैं:
\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction processValue(value: unknown) {\n if (isString(value)) {\n // TypeScript जानता है कि value एक स्ट्रिंग है\n console.log(value.toUpperCase());\n } else {\n console.log('यह स्ट्रिंग नहीं है');\n }\n}\n\nvalue is string पर ध्यान दें — यह एक प्रकार प्रेडिकेट है। यह TypeScript को संकेत देता है कि जाँच के बाद वेरिएबल एक निश्चित प्रकार का है। यह शुद्ध इंट्रोस्पेक्शन है: हम प्रकार को देखते हैं, लेकिन बदलते नहीं।
Reflect API के माध्यम से रिफ्लेक्शन
\n\nReflect ऑब्जेक्ट JavaScript में रिफ्लेक्शन का एक अंतर्निहित तंत्र है। यह उन क्रियाओं को करने की अनुमति देता है जो पहले 'जादुई' मेथड्स से की जाती थीं, लेकिन अब एकीकृत हैं। यहाँ कुछ उदाहरण हैं:
const user = {\n name: 'अलेक्सेई',\n age: 30,\n};\n\n// इंट्रोस्पेक्शन — कुंजियों की सूची प्राप्त करना\nconsole.log(Reflect.ownKeys(user)); // ['name', 'age']\n\n// रिफ्लेक्शन — गतिशील रूप से गुण पढ़ना\nconst propertyName = 'name';\nconsole.log(Reflect.get(user, propertyName)); // 'अलेक्सेई'\n\n// रिफ्लेक्शन — गतिशील रूप से गुण सेट करना\nReflect.set(user, 'name', 'मारिया');\nconsole.log(user.name); // 'मारिया'\n\nReflect पुराने user[prop] से बेहतर क्यों है? पहला, यह सेटिंग ऑपरेशन के लिए boolean लौटाता है, जो जाँच के लिए सुविधाजनक है। दूसरा, यह प्रॉक्सी और प्रॉपर्टी डिस्क्रिप्टर के साथ सही ढंग से काम करता है। TypeScript के लिए यह विशेष रूप से महत्वपूर्ण है, क्योंकि रिफ्लेक्शन आवश्यकता पड़ने पर स्टैटिक टाइपिंग को बायपास करने की अनुमति देता है।
डेकोरेटर: स्टेरॉयड पर रिफ्लेक्शन
\n\nडेकोरेटर शायद TypeScript में रिफ्लेक्शन का सबसे उज्ज्वल उदाहरण हैं। वे क्लासेस, मेथड्स, प्रॉपर्टीज और पैरामीटर्स को एनोटेट करने और फिर उनके व्यवहार को बदलने की अनुमति देते हैं। TypeScript 5.0 संस्करण से, डेकोरेटर मानक (stage 3) बन गए हैं।
\n\nयहाँ एक मेथड कॉल को लॉग करने के लिए एक सरल डेकोरेटर दिखाया गया है:
\n\nfunction logMethod(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor\n) {\n const originalMethod = descriptor.valu