रनटाइम पर क्लास नाम की आवश्यकता क्यों?
\n\nकल्पना करें: आप TypeScript में एक जटिल सिस्टम लिख रहे हैं। आपके पास क्लासेज का एक पदानुक्रम है — User, Admin, Moderator। कोड की गहराई में कहीं आपको एक ऑब्जेक्ट मिलता है, लेकिन पता नहीं यह वास्तव में क्या है। कंसोल में आपको सिर्फ object दिखता है।
या फिर आप एक लॉगर बना रहे हैं जो सिर्फ [Object] नहीं, बल्कि एक सार्थक क्लास नाम दिखाए: [User: John]। या आप एक डेकोरेटर लिख रहे हैं जो ऑब्जेक्ट के प्रकार के आधार पर तय करे कि उसे कैसे प्रोसेस करना है।
यहीं पर Stack Overflow पर हज़ारों बार देखा गया सवाल काम आता है: "रनटाइम पर ऑब्जेक्ट का क्लास नाम प्राप्त करें"। आज हम सिर्फ जवाब नहीं देंगे, बल्कि TypeScript और JavaScript के अंदरूनी हिस्से में झांकेंगे ताकि समझ सकें कि यह वास्तव में कैसे काम करता है।
\n\nहाँ, TypeScript JavaScript का एक सुपरसेट है। कंपाइलेशन के बाद सभी टाइप्स गायब हो जाते हैं। लेकिन क्लास का नाम कोई टाइप नहीं है, यह प्रोटोटाइप का एक गुण है। और यह रनटाइम में हमारे साथ रहता है।
\n\nसबसे आसान तरीका: constructor.name
\n\nअगर आपने कभी यह सवाल गूगल किया है, तो आपने शायद यह एक-लाइनर देखा होगा:
\n\nclass User {\n constructor(public name: string) {}\n}\n\nconst user = new User("आलिया");\nconsole.log(user.constructor.name); // "User"\n\nकाम करता है? हाँ। तेज़ है? हाँ। लेकिन इसमें कुछ बारीकियाँ हैं जो आपको परेशान कर सकती हैं अगर आप नहीं जानते कि यह कैसे काम करता है।
\n\nयह अंदरूनी रूप से कैसे काम करता है?
\n\nJavaScript में हर ऑब्जेक्ट में एक constructor प्रॉपर्टी होती है। यह उस फंक्शन का रेफरेंस है जिसने इस ऑब्जेक्ट को बनाया। और हर फंक्शन (क्लास भी एक फंक्शन है) में एक name प्रॉपर्टी होती है।
जब आप user.constructor.name लिखते हैं, तो इंजन यह करता है:
- \n
- ऑब्जेक्ट
userकी प्रोटोटाइप चेन पर चलता है। \n User.prototypeपरconstructorप्रॉपर्टी ढूंढता है। \n - कंस्ट्रक्टर फंक्शन
Userकाnameपढ़ता है। \n
यह एक सस्ता ऑपरेशन है, लेकिन मुफ्त नहीं है। ज़्यादातर मामलों में आपको इसका पता भी नहीं चलेगा।
\n\nconstructor.name कब काम नहीं करेगा?
\n\nयहाँ एक क्लासिक समस्या है:
\n\nconst obj = Object.create(null);\nconsole.log(obj.constructor); // undefined\n// console.log(obj.constructor.name); // TypeError!\n\nObject.create(null) से बनाए गए ऑब्जेक्ट में कोई प्रोटोटाइप नहीं होता। इसमें constructor नहीं है। सावधान रहें।
दूसरा मामला है मिनिफिकेशन। अगर आप Webpack या Terser जैसे बंडलर का उपयोग करते हैं जो क्लासेज का नाम बदल देते हैं, तो constructor.name कुछ ऐसा लौटा सकता है जैसे t या e। यह सिर्फ प्रोडक्शन में समस्या है, लेकिन इसके बारे में जानना ज़रूरी है।
विकल्प: instanceof और कस्टम जाँच
\n\nकभी-कभी आपको सिर्फ नाम नहीं, बल्कि यह जाँच चाहिए: "क्या यह ऑब्जेक्ट क्लास X का इंस्टेंस है?"
\n\nclass Animal {}\nclass Dog extends Animal {}\n\nconst dog = new Dog();\n\nconsole.log(dog instanceof Dog); // true\nconsole.log(dog instanceof Animal); // true\nconsole.log(dog instanceof Object); // true\n\ninstanceof प्रोटोटाइप चेन के माध्यम से काम करता है। यह जाँचता है कि क्या Dog.prototype ऑब्जेक्ट dog की प्रोटोटाइप चेन में मौजूद है। अगर हाँ, तो true।
लेकिन instanceof आपको नाम के साथ एक स्ट्रिंग नहीं देता। यह सिर्फ बूलियन वैल्यू देता है। लॉग या सीरियलाइज़ेशन के लिए यह उपयुक्त नहीं है।
संयोजन: जाँच + नाम
\n\nआप एक यूटिलिटी लिख सकते हैं जो पहले टाइप चेक करे और फिर नाम लौटाए:
\n\nfunction getClassName(obj: any): string | null {\n if (obj === null || obj === undefined) return null;\n if (typeof obj !== 'object' && typeof obj !== 'function') return null;\n\n // Object.create(null) से सुरक्षा\n if (!obj.constructor) return 'Object (कोई प्रोटोटाइप नहीं)';\n\n const name