typescript - टाइपस्क्रिप्ट में यूनियन स्ट्रिंग के रूप में एनम कीज प्राप्त करने के लिए सामान्य प्रकार?



generics enums (1)

नहीं, उपभोक्ता को उस वस्तु को संदर्भित करने के लिए typeof MyEnum का उपयोग करने की आवश्यकता होगी जिसकी कुंजी A , B और C

लंबी अवधि का अहद, जिसे आप पहले से ही जानते हैं

जैसा कि आप जानते हैं, टाइपस्क्रिप्ट जावास्क्रिप्ट में एक स्थिर प्रकार की प्रणाली को जोड़ता है, और उस प्रकार की प्रणाली कोड ट्रांसप्लड होने पर मिट जाती है। टाइपस्क्रिप्ट का वाक्य-विन्यास ऐसा है कि कुछ अभिव्यक्तियाँ और कथन उन मूल्यों को संदर्भित करते हैं जो रनटाइम पर मौजूद हैं, जबकि अन्य अभिव्यक्तियाँ और कथन उन प्रकारों को संदर्भित करते हैं जो केवल डिज़ाइन / संकलन समय पर मौजूद हैं। मानों के प्रकार हैं, लेकिन वे स्वयं प्रकार नहीं हैं। महत्वपूर्ण रूप से, कोड में कुछ स्थान हैं जहां संकलक एक मान की उम्मीद करेगा और अभिव्यक्ति की व्याख्या करेगा यदि यह संभव हो तो एक मूल्य के रूप में पाता है, और अन्य स्थानों पर जहां संकलक एक प्रकार की उम्मीद करेगा और यदि संभव हो तो एक प्रकार के रूप में मिलने वाले अभिव्यक्ति की व्याख्या करेगा।

संकलक परवाह नहीं करता है या भ्रमित हो जाता है यदि एक अभिव्यक्ति के लिए मूल्य और एक प्रकार दोनों के रूप में व्याख्या करना संभव है। उदाहरण के लिए, निम्न कोड में null के दो स्वादों के साथ यह पूरी तरह से खुश है:

let maybeString: string | null = null;

null का पहला उदाहरण एक प्रकार है और दूसरा मूल्य है। इससे भी कोई समस्या नहीं है

let Foo = {a: 0};
type Foo = {b: string};   

जहां पहला Foo एक नामित मान है और दूसरा Foo एक नामित प्रकार है। ध्यान दें कि Foo का मान {a: number} , जबकि Foo का प्रकार {b: string} । वे एक जैसे नहीं हैं।

यहां तक ​​कि typeof ऑपरेटर दोहरे जीवन का नेतृत्व करता है। typeof x टाइप टाइप typeof x हमेशा एक मूल्य होने के लिए x उम्मीद करता है , लेकिन typeof x खुद संदर्भ के आधार पर एक मूल्य या प्रकार हो सकता है:

let bar = {a: 0};
let TypeofBar = typeof bar; // the value "object"
type TypeofBar = typeof bar; // the type {a: number}

लाइन let TypeofBar = typeof bar; जावास्क्रिप्ट के माध्यम से यह कर देगा, और यह रनटाइम पर जावास्क्रिप्ट टाइपोफ़ ऑपरेटर का उपयोग करेगा और एक स्ट्रिंग का उत्पादन करेगा। लेकिन type TypeofBar = typeof bar ; मिटा दिया गया है, और यह टाइपस्क्रिप्ट टाइप करने के लिए टाइपस्क्रिप्ट टाइप करने के लिए असाइन किया गया टाइप टाइप की जांच करने के लिए टाइपस्क्रिप्ट टाइप क्वेरी ऑपरेटर का उपयोग कर रहा है।

अब, टाइपस्क्रिप्ट में अधिकांश भाषा का निर्माण होता है जो नाम पेश करते हैं या तो एक नामित मान या एक नाम प्रकार बनाते हैं। यहां कुछ नामित मूल्यों के परिचय दिए गए हैं:

const value1 = 1;
let value2 = 2;
var value3 = 3;
function value4() {}

और यहाँ कुछ प्रकार के नाम दिए गए हैं:

interface Type1 {}
type Type2 = string;

लेकिन कुछ घोषणाएं हैं जो एक नामित मान और एक नामित प्रकार दोनों का निर्माण करती हैं , और, Foo ऊपर की तरह, नामित मूल्य का प्रकार नाम प्रकार नहीं है । बड़े लोग class और enum :

class Class { public prop = 0; }
enum Enum { A, B }

यहां, Class का प्रकार Class की आवृत्ति का प्रकार है, जबकि मान Class कंस्ट्रक्टर ऑब्जेक्ट है। और typeof Class नहीं है:

const instance = new Class();  // value instance has type (Class)
// type (Class) is essentially the same as {prop: number};

const ctor = Class; // value ctor has type (typeof Class)
// type (typeof Class) is essentially the same as new() => Class;

और, टाइप Enum एन्यूमरेशन के एक तत्व का प्रकार है; प्रत्येक तत्व के प्रकारों का एक संघ। जबकि मान Enum एक वस्तु है जिसकी कुंजी A और B , और जिनके गुण गणन के तत्व हैं। और typeof Enum नहीं है:

const element = Math.random() < 0.5 ? Enum.A : Enum.B; 
// value element has type (Enum)
// type (Enum) is essentially the same as Enum.A | Enum.B
//  which is a subtype of (0 | 1)

const enumObject = Enum;
// value enumObject has type (typeof Enum)
// type (typeof Enum) is essentially the same as {A: Enum.A; B: Enum.B}
//  which is a subtype of {A:0, B:1}

अब आपके सवाल का समर्थन करने का तरीका। आप एक प्रकार के ऑपरेटर का आविष्कार करना चाहते हैं जो इस तरह काम करता है:

type KeysOfEnum = EnumKeysAsStrings<Enum>;  // "A" | "B"

जहाँ आप Enum टाइप करते हैं, और ऑब्जेक्ट Enum की चाबी निकालते हैं। लेकिन जैसा कि आप ऊपर देखते हैं, Enum का प्रकार ऑब्जेक्ट Enum के समान नहीं है । और दुर्भाग्य से प्रकार मूल्य के बारे में कुछ भी नहीं जानता है। यह कहने जैसा है:

type KeysOfEnum = EnumKeysAsString<0 | 1>; // "A" | "B"

स्पष्ट रूप से यदि आप इसे इस तरह लिखते हैं, तो आप देखेंगे कि कुछ भी नहीं है जो आप टाइप 0 | 1 लिए कर सकते हैं 0 | 1 जो "A" | "B" प्रकार का उत्पादन करेगा "A" | "B" "A" | "B" । इसे काम करने के लिए, आपको इसे एक प्रकार से पास करना होगा जो मैपिंग के बारे में जानता हो। और वह टाइप है typeof Enum ...

type KeysOfEnum = EnumKeysAsStrings<typeof Enum>; 

जो पसंद है

type KeysOfEnum = EnumKeysAsString<{A:0, B:1}>; // "A" | "B"

जो संभव है ... यदि type EnumKeysAsString<T> = keyof T

इसलिए आप उपभोक्ता को typeof Enum निर्दिष्ट करते हुए फंस गए हैं। क्या वहाँ काम कर रहे हैं? ठीक है, आप शायद कुछ ऐसा उपयोग कर सकते हैं जो एक फ़ंक्शन के रूप में एक मूल्य है?

 function enumKeysAsString<TEnum>(theEnum: TEnum): keyof TEnum {
   // eliminate numeric keys
   const keys = Object.keys(theEnum).filter(x => 
     (+x)+"" !== x) as (keyof TEnum)[];
   // return some random key
   return keys[Math.floor(Math.random()*keys.length)]; 
 }

तब आप कॉल कर सकते हैं

 const someKey = enumKeysAsString(Enum);

और someKey का प्रकार "A" | "B" "A" | "B" । हाँ, लेकिन फिर इसे टाइप करने के लिए आपको इसे क्वेरी करना होगा:

 type KeysOfEnum = typeof someKey;

जो आपको फिर से typeof का उपयोग करने के लिए typeof और आपके समाधान से भी अधिक क्रिया है, खासकर जब से आप ऐसा नहीं कर सकते हैं:

 type KeysOfEnum = typeof enumKeysAsString(Enum); // error

Blegh। माफ़ कीजिये।

संक्षेप में दुहराना:

  • यह नहीं हो सकता;
  • TYPES और वाल्व BLAH BLAH;
  • अभी भी स्थिति नहीं है;
  • माफ़ कीजिये।

आशा है कि कुछ समझ में आता है। सौभाग्य।

निम्न प्रकार के एनम पर विचार करें:

enum MyEnum { A, B, C };

अगर मुझे एक और प्रकार चाहिए, जो उस एनम की कुंजियों का संघटित तार है, तो मैं निम्नलिखित कर सकता हूं:

type MyEnumKeysAsStrings = keyof typeof MyEnum;  // "A" | "B" | "C"

यह बहुत उपयोगी है।

अब मैं एक सामान्य प्रकार बनाना चाहता हूं जो सार्वभौमिक रूप से इस तरह से एनमों पर काम करता है, ताकि मैं इसके बजाय कह सकूं:

type MyEnumKeysAsStrings = AnyEnumKeysAsStrings<MyEnum>;

मुझे लगता है कि इसके लिए सही वाक्यविन्यास होगा:

type AnyEnumKeysAsStrings<TEnum> = keyof typeof TEnum; // TS Error: 'TEnum' only refers to a type, but is being used as a value here.

लेकिन यह एक संकलित त्रुटि उत्पन्न करता है: "'टेन्नम' केवल एक प्रकार को संदर्भित करता है, लेकिन यहां एक मूल्य के रूप में उपयोग किया जा रहा है।"

यह अप्रत्याशित और दुखद है। जेनेरिक की घोषणा के दाईं ओर से टाइपोफ़ को ड्रॉप करके और विशिष्ट प्रकार की घोषणा में इसे टाइप पैरामीटर में जोड़कर मैं इसके आसपास अधूरा काम कर सकता हूं:

type AnyEnumAsUntypedKeys<TEnum> = keyof TEnum;
type MyEnumKeysAsStrings = AnyEnumAsUntypedKeys<typeof MyEnum>; // works, but not kind to consumer.  Ick.

मुझे यह वर्कअराउंड पसंद नहीं है, क्योंकि इसका मतलब है कि उपभोक्ता को जेनेरिक पर टाइपोफ के इस icky निर्दिष्ट करने के लिए याद रखना होगा।

क्या कोई वाक्यविन्यास है जो मुझे जेनेरिक प्रकार को निर्दिष्ट करने की अनुमति देगा जैसा कि मैं शुरू में चाहता हूं, उपभोक्ता के प्रति दयालु होना चाहिए?





enums