परिचय: जेनेरिक के बिना TypeScript अपनी आधी ताकत क्यों खो देता है?
\n\nकल्पना करें कि आप एक आर्किटेक्ट हैं, जो हर बार एक इमारत को शुरू से डिज़ाइन करता है, भले ही आपको बस एक और ऐसा ही गैरेज बनाना हो। लगभग ऐसा ही महसूस करता है वह डेवलपर जो संख्याओं, स्ट्रिंग्स और ऐरे के लिए एक ही फंक्शन को बार-बार लिखता है, बिना TypeScript generics का उपयोग किए। परिचित लगता है? यदि आपने TypeScript में बुनियादी प्रकारों में महारत हासिल कर ली है, लेकिन महसूस करते हैं कि आप बहुत अधिक डुप्लिकेट कोड लिख रहे हैं, तो यह लेख आपके लिए है।
\n\nGenerics (जेनेरिक) एक ऐसा तंत्र है जो आपको ऐसे घटक (फंक्शन, क्लास, इंटरफ़ेस) बनाने की अनुमति देता है जो एक विशिष्ट प्रकार के बजाय विभिन्न प्रकारों के साथ काम करते हैं। कोड को कॉपी करने के बजाय, आप इसे एक बार लिखते हैं, और प्रकार स्वचालित रूप से सेट हो जाता है। इस लेख में, हम समझेंगे कि TypeScript में सामान्यीकृत प्रोग्रामिंग कैसे काम करती है, वास्तविक कोड उदाहरण दिखाएंगे, और व्यावहारिक सुझाव देंगे जो आपके कोड को साफ और सुरक्षित बनाएंगे।
\n\nहम PythonLib हैं, और आज हम TypeScript के बारे में बात कर रहे हैं, क्योंकि इसके बिना आधुनिक फ्रंटएंड डेवलपमेंट अकल्पनीय है। चलिए शुरू करते हैं!
\n\nTypeScript में जेनेरिक क्या हैं और उनकी आवश्यकता क्यों है?
\n\nआइए एक सरल उदाहरण से शुरू करते हैं। मान लीजिए कि आप एक ऐसा फंक्शन लिखना चाहते हैं जो दिए गए आर्गुमेंट को वापस करता है (identity फंक्शन)।
\n\n// जेनेरिक के बिना — any का उपयोग करना पड़ता है\nfunction identity(arg: any): any {\n return arg;\n}\n\n// या प्रत्येक प्रकार के लिए ओवरलोड लिखना पड़ता है\nfunction identityNumber(arg: number): number { return arg; }\nfunction identityString(arg: string): string { return arg; }\n\nपहला विकल्प टाइपिंग को खत्म कर देता है — आप प्रकार के बारे में जानकारी खो देते हैं। दूसरा विकल्प आपको ढेर सारे समान फंक्शन बनाने के लिए मजबूर करता है। TypeScript जेनेरिक इस समस्या को सुंदर ढंग से हल करते हैं:
\n\nfunction identity<T>(arg: T): T {\n return arg;\n}\n\nconst num = identity<number>(42); // प्रकार number\nconst str = identity('hello'); // प्रकार string (प्रकार अनुमान)\nconst bool = identity(true); // प्रकार boolean\n\nप्रतीक <T> एक प्रकार पैरामीटर है। आप इसे जो चाहें नाम दे सकते हैं (अक्सर T, U, V का उपयोग किया जाता है), लेकिन यदि कई हों तो सार्थक नाम देना बेहतर होता है। जब आप फंक्शन को कॉल करते हैं, TypeScript T के स्थान पर वास्तविक प्रकार डालता है। यदि प्रकार स्पष्ट रूप से निर्दिष्ट नहीं है, तो कंपाइलर इसे आर्गुमेंट से स्वचालित रूप से अनुमान लगाएगा।
इस प्रकार, सामान्यीकृत प्रकार (Generics) आपको सख्त टाइपिंग बनाए रखने की अनुमति देते हैं, जहाँ पहले any का उपयोग करना पड़ता था। इससे बग की संख्या कम होती है और कोड स्व-दस्तावेजीकरण बन जाता है।
जेनेरिक का सिंटैक्स: सरल से जटिल तक
\n\nGeneric फंक्शन
\n\nहमने पहले ही एक बुनियादी उदाहरण देखा है। आइए इसे जटिल बनाते हैं: एक फंक्शन जो एक ऐरे लेता है और उसका पहला एलिमेंट लौटाता है।
\n\nfunction getFirst<T>(arr: T[]): T | undefined {\n return arr[0];\n}\n\nconst firstNumber = getFirst([1, 2, 3]); // number | undefined\nconst firstString = getFirst(['a', 'b', 'c']); // string | undefined\n\nध्यान दें: T[], Array<T> का संक्षिप्त रूप है। आप किसी भी रूप का उपयोग कर सकते हैं।
Generic इंटरफ़ेस
\n\nजेनेरिक वाले इंटरफ़ेस डेटा संरचनाओं का वर्णन करने के लिए एक शक्तिशाली उपकरण हैं। उदाहरण के लिए, एक टाइप किया गया API प्रतिक्रिया:
\n\ninterface ApiResponse<T> {\n data: T;\n status: number;\n message: string;\n}\n\n// उपयोग\nconst userResponse: ApiResponse<{ id: number; name: string }> = {\n data: { id: 1, name: 'Alice' },\n status: 200,\n message: 'OK'\n};\n\nअब एक इंटरफ़ेस उपयोगकर्ताओं, उत्पादों, ऑर्डरों के लिए प्रतिक्रियाओं का वर्णन कर सकता है — बस सही प्रकार डालें।
\n\nGeneric क्लास
\n\nक्लास भी सामान्यीकृत हो सकते हैं। एक क्लासिक उदाहरण कतार (Queue) है:
\n\nc