परिचय: TypeScript आपके कोड पर क्यों भड़कता है?
\n\nक्या आपने कभी TypeScript में ऐसा कोड लिखा है जो बिल्कुल तार्किक लगता है, लेकिन कंपाइलर अचानक एक डरावनी त्रुटि देता है? यदि आपने "An index signature parameter type cannot be a union type. Consider using a mapped object type instead" संदेश का सामना किया है - तो आप अकेले नहीं हैं। यह त्रुटि Stack Overflow पर सबसे लोकप्रिय प्रश्नों में से एक है (हज़ारों व्यूज़!), और यह अक्सर अनुभवी डेवलपर्स को भी हैरान कर देती है।
\n\nइस लेख में, हम केवल त्रुटि को ठीक करने का तरीका नहीं दिखाएंगे। हम समझेंगे कि TypeScript क्यों इतना सख्त है, और mapped object types का उपयोग कैसे करें ताकि आपका कोड न केवल काम करे बल्कि अधिक सुरक्षित भी हो। चलिए शुरू करते हैं!
\n\nindex signature क्या है और इसकी आवश्यकता क्यों है?
\n\nकल्पना करें कि आप एक ऐसा ऑब्जेक्ट बना रहे हैं जिसकी कुंजियाँ स्ट्रिंग हैं और मान संख्याएँ हैं। उदाहरण के लिए, उत्पादों की कीमतों का एक शब्दकोश:
\n\n// सामान्य ऑब्जेक्ट\nconst prices = {\n apple: 100,\n banana: 50,\n cherry: 200\n};\n\nलेकिन क्या होगा यदि आप TypeScript को बताना चाहते हैं: "देखो, इस ऑब्जेक्ट में कोई भी स्ट्रिंग कुंजी हो सकती है, और सभी मान संख्याएँ होंगी"? इसके लिए index signature की आवश्यकता है - एक विशेष सिंटैक्स जो ऑब्जेक्ट के सभी गुणों के लिए एक टेम्पलेट का वर्णन करता है:
\n\n// Index signature: [key: string]: number\ninterface PriceMap {\n [key: string]: number;\n}\n\nconst prices: PriceMap = {\n apple: 100,\n banana: 50\n};\n\nयहाँ [key: string]: number ही index signature है। यह कहता है: "कुंजियाँ स्ट्रिंग हैं, मान संख्याएँ हैं"। सरल है, है ना?
union-प्रकारों में समस्या क्या है?
\n\nअब कल्पना करें कि आप संभावित कुंजियों को केवल दो विकल्पों तक सीमित करना चाहते हैं: 'name' या 'age'। ऐसा लिखना तार्किक लगता है:
// ❌ त्रुटि! ऐसा नहीं कर सकते\ninterface Person {\n [key: 'name' | 'age']: string | number;\n}\n\nऔर तब TypeScript वही त्रुटि देता है: "An index signature parameter type cannot be a union type. Consider using a mapped object type instead"।
\n\nक्यों? क्योंकि index signature असीमित कुंजियों के सेट का वर्णन करने के लिए है। यदि आप कुंजियों की एक विशिष्ट सूची निर्धारित करना चाहते हैं, तो यह एक टेम्पलेट नहीं, बल्कि संरचना का सटीक विवरण है। TypeScript इन अवधारणाओं को मिश्रित करने की अनुमति नहीं देता।
\n\nत्रुटि कैसे ठीक करें? Mapped Object Type का उपयोग करें
\n\nकंपाइलर स्वयं जो समाधान सुझाता है वह है mapped object type (मैप किया गया ऑब्जेक्ट प्रकार) का उपयोग करना। यह जटिल लगता है, लेकिन वास्तव में यह union-प्रकार से सभी कुंजियों को "पुनरावृत्त" करने और प्रत्येक के लिए एक गुण बनाने का एक तरीका है।
\n\nयह इस प्रकार दिखता है:
\n\n// ✅ सही: mapped type का उपयोग करें\ntype Person = {\n [K in 'name' | 'age']: K extends 'name' ? string : number;\n};\n\n// या एक सरल संस्करण, यदि मानों के प्रकार समान हैं:\ntype PersonSimple = {\n [K in 'name' | 'age']: string | number;\n};\n\nसिंटैक्स [K in 'name' | 'age'] को समझते हैं:
- \n
K- एक चर है जो बारी-बारी से union-प्रकार से प्रत्येक मान लेता है ('name', फिर'age')। \n in- एक कीवर्ड है जो प्रकारों पर "लूप" शुरू करता है। \n 'name' | 'age'- हमारी कुंजियों का सेट। \n
परिणामस्वरूप, TypeScript दो विशिष्ट गुणों वाला एक ऑब्जेक्ट बनाएगा: name और age। त्रुटि गायब हो गई!
विभिन्न मान प्रकारों के साथ उदाहरण
\n\nअक्सर ऐसा होता है कि विभिन्न कुंजियों के लिए विभिन्न प्रकार के मान होने चाहिए। सशर्त प्रकारों (conditional types) की मदद से इसे सुरुचिपूर्ण ढंग से हल किया जाता है:
\n\ntype Config = {\n [K in 'host' | 'port' | 'debug']: \n K extends 'host' ? string :\n K extends 'port' ? number :\n boolean;\n};\n\n// अब: