TypeScript में मेटाप्रोग्रामिंग: कोड जो कोड लिखता है

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: टाइप्स में छिपा जादू

\n\n

कल्पना करें कि आप सिर्फ कोड नहीं लिख रहे हैं, बल्कि कंपाइलर के लिए निर्देशों का एक सेट लिख रहे हैं, जो आपके नियमों के आधार पर सुरक्षित और स्व-दस्तावेजी संरचनाएं उत्पन्न करता है। यही है TypeScript में मेटाप्रोग्रामिंग — टाइप स्तर पर काम करने वाला कोड जो कंपाइलेशन के दौरान अन्य टाइप्स का विश्लेषण और रूपांतरण करता है।

\n\n

कई डेवलपर्स बुनियादी generics और interfaces पर ही रुक जाते हैं, उन्हें पता भी नहीं होता कि infer, extends और conditional constructs जैसे कीवर्ड्स के पीछे कितना शक्तिशाली शस्त्रागार छिपा है। इस लेख में हम TypeScript मेटाप्रोग्रामिंग की उन्नत तकनीकों को समझेंगे, जो आपको भाषा के एक सामान्य उपयोगकर्ता से उसके वास्तुकार में बदल देंगी।

\n\n

1. कंडीशनल टाइप्स: टाइप स्तर पर if

\n\n

कंडीशनल टाइप्स किसी भी type-level प्रोग्रामिंग की नींव हैं। ये टर्नरी ऑपरेटर की तरह काम करते हैं, लेकिन टाइप सिस्टम के स्तर पर:

\n\n
type IsString<T> = T extends string ? "yes" : "no";\n\ntype Test1 = IsString<"hello">;   // "yes"\ntype Test2 = IsString<42>;        // "no"\n
\n\n

लेकिन असली जादू तब शुरू होता है जब हम इन्हें generics के साथ जोड़ते हैं। उदाहरण के लिए, एक ऐसा टाइप बनाएं जो किसी ऑब्जेक्ट के केवल स्ट्रिंग कीज़ को निकाले:

\n\n
type StringKeys<T> = {\n  [K in keyof T]: T[K] extends string ? K : never\n}[keyof T];\n\ninterface User {\n  name: string;\n  age: number;\n  email: string;\n}\n\ntype UserStringKeys = StringKeys<User>; // "name" | "email"\n
\n\n

यह उदाहरण दिखाता है कि कैसे TypeScript के उन्नत टाइप्स कंपाइलेशन के समय डेटा संरचनाओं को फ़िल्टर और रूपांतरित करने की अनुमति देते हैं। आप सचमुच ऐसी लॉजिक प्रोग्राम कर रहे हैं जो कोड के रनटाइम में जाने से पहले ही निष्पादित हो जाती है।

\n\n

2. Infer: दूसरे टाइप्स से टाइप निकालना

\n\n

कीवर्ड infer शायद TypeScript मेटाप्रोग्रामिंग के शस्त्रागार में सबसे शक्तिशाली उपकरण है। यह आपको टाइप के "अंदर झांकने" और उसके घटक भागों को निकालने की अनुमति देता है। आइए एक क्लासिक उदाहरण देखें — किसी फंक्शन के रिटर्न वैल्यू का टाइप प्राप्त करना:

\n\n
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;\n\ntype Fn = (x: number) => string;\ntype FnReturn = ReturnType<Fn>; // string\n
\n\n

लेकिन infer और भी बहुत कुछ कर सकता है। आइए किसी फंक्शन के पहले आर्गुमेंट का टाइप निकालें:

\n\n
type FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;\n\ntype Handler = (id: number, name: string) => void;\ntype HandlerFirstArg = FirstArg<Handler>; // number\n
\n\n

और प्रॉमिसेज के रिकर्सिव पार्सिंग के बारे में क्या ख्याल है? एक ऐसा टाइप बनाएं जो सभी नेस्टेड Promise को "अनरैप" करता है:

\n\n
type UnwrapPromise<T> = T extends Promise<infer U> ? UnwrapPromise<U> : T;\n\ntype DeepPromise = Promise<Promise<Promise<number>>>;\ntype Unwrapped = UnwrapPromise<DeepPromise>; // number\n
\n\n

रिकर्शन पर ध्यान दें — यह सबसे सुंदर TypeScript की उन्नत तकनीकों में से एक है, जो अनंत रूप से नेस्टेड संरचनाओं को संभालने की अनुमति देती है।

\n\n

3. मैप्ड टाइप्स: ऑब्जेक्ट्स का रूपांतरण

\n\n

Mapped types आपको मौजूदा टाइप्स के आधार पर नए टाइप्स बनाने की अनुमति देते हैं, उनकी कीज़ को पुनरावृत्त करके। यह सामान्यीकृत उपयोगिताएं बनाने के लिए एक अपरिहार्य उपकरण है:

\n\n
type Readonly<T> = {\n  readonly [K in keyof T]: T[K];\n};\n\ntype Partial<T> = {\n  [K in keyof T]?: T[K];\n};\n
\n\n

लेकिन हम और आगे जा सकते हैं। एक ऐसा टाइप बनाएं जो सभी प्रॉपर्टीज़ को वैकल्पिक बनाता है, लेकिन केवल तभी जब वे स्ट्रिंग हों:

\n\n
type PartialStringProps<T> = {\n  [K in keyof T]: T[K] extends string ? T[K] | undefined : T[K];\n};\n\ninterface Config {\n  nam                

ब्लॉग

पुस्तक अनुशंसाएँ