कंडीशनल टाइप्स की वितरणशीलता, infer के साथ पैटर्न मैचिंग, और never, any तथा boolean जैसे किनारे के मामलों में महारत हासिल करें।
इस पाठ को Kodokon में खोलेंकंडीशनल टाइप्स टाइप सिस्टम का ब्रांचिंग तंत्र हैं: T extends U ? X : Y कंपाइलर से पूछता है कि क्या T को U को असाइन किया जा सकता है, फिर एक शाखा चुनता है। ReturnType, Exclude, या Awaited जैसी सभी मानक यूटिलिटीज़ इन्हीं पर बनी हैं। इस स्तर पर सवाल यह नहीं है कि इन्हें कैसे लिखें, बल्कि यह है कि ठीक-ठीक कैसे अनुमान लगाएं कि कंपाइलर इनका मूल्यांकन कैसे करता है, खासकर जब यूनियन और never शामिल हों।
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">;
// true
type B = IsString<string | number>;
// boolean, not false!मुख्य व्यवहार है वितरणशीलता (distributivity): जब परखा जा रहा टाइप एक नंगा टाइप पैरामीटर (naked type parameter) होता है (जो किसी ट्यूपल, ऐरे, या इंटरसेक्शन में लिपटा न हो), तो कंडीशनल यूनियन के प्रत्येक सदस्य पर अलग-अलग लागू होता है, और फिर परिणामों को जोड़ दिया जाता है। इसीलिए IsString<string | number> की गणना true | false होती है, जो कि boolean है। इस वितरण को अक्षम करने के लिए, दोनों पक्षों को एक ट्यूपल में लपेटें: [T] extends [U]। एक भयानक किनारे का मामला: never खाली यूनियन है; शून्य सदस्यों पर वितरण किसी भी शाखा का मूल्यांकन नहीं करता, और आपने चाहे जो शाखा लिखी हो, परिणाम never ही रहता है।
type ToArray<T> = T extends unknown ? T[] : never;
type NoDist<T> = [T] extends [unknown] ? T[] : never;
type A = ToArray<string | number>;
// string[] | number[]
type B = NoDist<string | number>;
// (string | number)[]
type IsNever<T> = [T] extends [never] ? true : false;
type C = IsNever<never>; // true thanks to the tupleinfer कीवर्ड एक ऐसा टाइप वेरिएबल प्रस्तुत करता है जो पैटर्न मैचिंग के माध्यम से पकड़ा जाता है: कंपाइलर परखे जा रहे टाइप की संरचना को पैटर्न से मिलाने की कोशिश करता है, और मैच सफल होने पर वेरिएबल को बांध देता है। आप एक ही नाम के साथ कई infer घोषणाएं रख सकते हैं: एक सहचर स्थिति (covariant position) में (उत्पादित मान, जैसे रिटर्न टाइप), उम्मीदवारों को एक यूनियन में मिला दिया जाता है; एक प्रतिचर स्थिति (contravariant position) में (फ़ंक्शन पैरामीटर), उन्हें एक इंटरसेक्शन में जोड़ा जाता है। यह नियम सीधे वेरिएंस से निकलता है: प्रत्येक दिशा में यही एकमात्र सुरक्षित विकल्प है।
type ElementOf<T> =
T extends readonly (infer E)[] ? E : never;
type FirstParam<T> =
T extends (arg: infer P) => unknown ? P : never;
type Merged<T> =
T extends { a: (x: infer P) => void;
b: (x: infer P) => void }
? P : never;
type M = Merged<{
a: (x: { id: string }) => void;
b: (x: { tag: string }) => void;
}>; // { id: string } & { tag: string }TypeScript 4.7 से, infer एक इनलाइन कंस्ट्रेंट स्वीकार करता है: infer N extends number कैप्चर को छानता है, और 4.8 से कंपाइलर एक संख्यात्मक स्ट्रिंग लिटरल को संख्या लिटरल में भी बदल देता है। एक और विनिर्देश की बारीकी: एक कंडीशनल टाइप जिसके इनपुट में अभी भी कोई अनसुलझा जेनेरिक पैरामीटर हो, वह स्थगित (deferred) रहता है; इसका मूल्यांकन केवल इंस्टैंसिएशन स्थल पर होता है, जिससे यह समझ आता है कि कुछ त्रुटियां केवल कॉलर के पक्ष में क्यों दिखती हैं।
type ToNumber<S extends string> =
S extends `${infer N extends number}` ? N : never;
type Port = ToNumber<"8080">; // the literal 8080
type Bad = ToNumber<"abc">; // neverExclude<boolean, true> क्या है?type IsNever<T> = T extends never ? true : false; के साथ, IsNever<never> क्या है?infer P जो फ़ंक्शन पैरामीटर स्थिति में रखे गए हों, वे उत्पन्न करते हैं: