2017-02-23 14 views
5

क्या हम टाइप स्क्रिप्ट में प्रतिबिंब का उपयोग सी # की तरह कर सकते हैं ताकि कक्षाओं की सूची प्राप्त हो सके जो एक निश्चित बेस क्लास को लागू करते हैं?टाइप स्क्रिप्ट में प्रतिबिंब का उपयोग करके एक निश्चित आधार वर्ग को लागू करने वाले बाल वर्ग कैसे प्राप्त करें?

उदाहरण के लिए, सांप और घोड़े बेस क्लास एनिमल को लागू करें। अब मुझे कक्षाएं प्राप्त करने की आवश्यकता है जो पशु को लागू करते हैं।

सी # बराबर कोड::

var childTypes = assembly.GetTypes().Where(_ => _.IsSubclassOf(typeof(Animal))); 

प्रकार स्क्रिप्ट कक्षाएं:

class Animal { 
} 

class Snake extends Animal { 
} 

class Horse extends Animal { 
} 
+1

यह वर्तमान में एक [गैर-लक्ष्य] (https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals) टाइपस्क्रिप्ट के लिए है। आप जिस वास्तविक समस्या को हल करने की कोशिश कर रहे हैं वह क्या है? –

+0

टाइपस्क्रिप्ट में अपनी कक्षाएं बनाने के लिए https://frhagn.github.io/Typewriter/ का उपयोग करने के बारे में कैसे? –

+0

@PaulBullivant मुझे वह उपकरण पसंद है लेकिन मुझे लगता है कि वह कुछ अलग दिख रहा है –

उत्तर

0

एक तरह से यह ट्रैक रखने के लिए किया जाएगा करने के लिए हम सी # में क्या कर सकते हैं के समान आपके द्वारा एक वैश्विक सरणी में बनाए गए सभी वर्ग:

var allClasses = [] 
function register(c) { 
    allClasses.push(c); 
} 
register(class Animal {}); 
register(class Snake extends Animal {}); 
register(class Horse extends Animal {}); 
register(class Car {}); 

और जब आप वर्गों है कि विशेष वर्ग से विरासत की जरूरत है, जैसा कि आप चाहते हैं को फ़िल्टर:

Object.values(allClasses).filter((c) => Animal.isPrototypeOf(c)) 

यह समाधान टाइपप्रति के लिए विशिष्ट नहीं है, यह शुद्ध जावास्क्रिप्ट के साथ भी काम करेंगे।

0

मुझे SOAP वेब सेवा से प्रतिक्रिया को deserialize करने की आवश्यकता थी। मैंने पहली बार लौटाए गए एक्सएमएल से ऑब्जेक्ट प्राप्त करने के लिए एक मौजूदा एसओएपी क्लाइंट का उपयोग किया और फिर एक JSON deserializer का उपयोग किया - http://cloudmark.github.io/Json-Mapping/ से - इस ऑब्जेक्ट को वास्तविक प्रकारों में deserialize करने के लिए।

समस्या यह थी कि लौटाई गई संपत्तियों में से एक को मूल प्रकार के रूप में घोषित किया गया था और वास्तव में कई अलग-अलग उप-प्रकारों के उदाहरण हो सकते थे।

मैंने इसे कक्षा सजावट बनाने के द्वारा हल किया जिसे मैं व्युत्पन्न प्रकारों पर लागू करता हूं। इस वर्ग सजावटी को बेस क्लास मिलती है और व्युत्पन्न कक्षा का वर्णन करते हुए मेटाडेटा लागू होती है।

निम्नलिखित कोड को समझने के लिए यह जानना आवश्यक है कि XML महत्वपूर्ण है -> JSON पार्सर एक $type संपत्ति यदि वेब सेवा से एक्सएमएल एक type विशेषता है जो इंगित करता है कि बहुरूपता खेल में होता है कहते हैं।

मूल मेटाडेटा जो बेस प्रकार पर लागू होता है वह एक्सएमएल से टाइप नाम और व्युत्पन्न प्रकार के निर्माता हैं।

मेटा डेटा पंजीकरण और वर्ग डेकोरेटर:

export interface IJsonPolymorphism { 
    name: string; 
    clazz: {new(): any}; 
} 

export function RegisterForPolymorphism(name: string) { 
    return (target) => { 
     let metadata = getJsonPolymorphism(target.__proto__); 
     if (!metadata) { 
      metadata = []; 
     } 
     metadata.push({name: name, clazz: target}); 
     target.__proto__ = Reflect.metadata(jsonPolymorphismMetadataKey, metadata)(target.__proto__); 
     return target; 
    }; 
} 

export function getJsonPolymorphism(target: any): IJsonPolymorphism[] { 
    return Reflect.getMetadata(jsonPolymorphismMetadataKey, target); 
} 

उपयोग:

// The base class 
export class PropertyBase { /*...*/ } 

// The derived classes 
// 

@RegisterForPolymorphism("b:PicklistProperty") 
export class PicklistProperty extends PropertyBase { /*...*/ } 
@RegisterForPolymorphism("b:TextProperty") 
export class TextProperty extends PropertyBase { /*...*/ } 

तार उस वर्ग डेकोरेटर करने के लिए पारित कर रहे हैं वेब से एक्सएमएल जवाब में type विशेषता का मान हैं सर्विस।

deserializer के कोड इस तरह यह का उपयोग करता है:

if (jsonObject["$type"]) { 
    const polymorphism = getJsonPolymorphism(clazz); 
    if (polymorphism && polymorphism.filter) { 
     const subclassDefinition = polymorphism.filter(x => x.name === jsonObject["$type"])[0]; 
     if (subclassDefinition && subclassDefinition.clazz) { 
      clazz = subclassDefinition.clazz; 
     } 
    } 
} 

असल में, clazz प्रकार के JSON ऑब्जेक्ट deserialize के निर्माता है और हम व्युत्पन्न प्रकार के निर्माता से बदल दें।

इस कोड में वर्तमान में प्रतिबंध है कि यह केवल पूरे श्रेणी के लिए सीधे आधार वर्ग तक मेटाडेटा जोड़ता है। लेकिन पेड़ को चलने के लिए RegisterForPolymorphism के अंदर कोड को समायोजित करके इसे आसानी से हल किया जा सकता है।

4

यदि आप ऐसी सुविधा पर निर्भरता लेने के इच्छुक हैं जो जल्द से जल्द बदलने की संभावना है, क्योंकि यह अप्रचलित विनिर्देश पर आधारित है, और यदि आप केवल कक्षाओं का उपयोग करने के इच्छुक हैं और इंटरफ़ेस नहीं हैं, तो आप इसका उपयोग करके इसे पूरा कर सकते हैं एक सजावटी

यहाँ एक उदाहरण है:

पदानुक्रम-tracked.ts

export default function hierarchyTracked(target: new (...args: any[]) => object) { 
    for (const proto of walkPrototypeChain(target)) { 
    if (!Object.hasOwnProperty.call(proto, 'extendedBy')) { 
     const extendedBy: typeof Function.extendedBy = []; 
     Object.defineProperty(proto, 'extendedBy', { 
     get:() => extendedBy 
     }); 
    } 
    // ! is used to suppress a strictNullChecks error on optional. 
    // This is OK since we know it is now defined. 
    proto.extendedBy!.push(target); 
    } 
} 

declare global { 
    interface Function { 
    // Declared as optional because not all classes are extended. 
    extendedBy?: Array<new (...args: any[]) => object>; 
    } 
} 

function* walkPrototypeChain(target: new (...args: any[]) => object) { 
    let proto = Reflect.getPrototypeOf(target); 
    while (proto && proto !== Object) { 
    yield proto; 
    proto = Reflect.getPrototypeOf(proto); 
    } 
} 

animals.ts

import hierarchyTracked from './hierarachy-tracked'; 

export class Animal { 
    alive = true; 
    static get slayable() {return true;} 
    static extinct = false; 
} 

@hierarchyTracked export class Snake extends Animal { 
    isEctotherm = true; 
} 

@hierarchyTracked export class Cobra extends Snake { 
    isDeadly = true; 
} 

@hierarchyTracked export class Horse extends Animal { 
    isEndotherm = true; 
} 
// logs 
Animal.extendedBy && Animal.extendedBy.map(Taxon => Taxon.name) 
    .forEach(name => { 
    console.log(name); 
    }); 
// Snake 
// Cobra 
// Horse 

Snake.extendedBy && Snake.extendedBy.map(Taxon => Taxon.name) 
    .forEach(name => { 
    console.log(name); 
    }); 
// Cobra 

वैश्विक राज्य और इसे करने के लिए उपाय करने की जरूरत नहीं है वास्तव में काफी साफ और स्पष्ट है।

यदि आप टाइपस्क्रिप्ट का उपयोग नहीं कर रहे हैं तो यह Babel 7 के साथ भी काम करता है। (ध्यान दें कि डेकोरेटर उपयोग के बारे में एक ही चेतावनियां ऊपर उल्लेख किया है अभी भी लागू)

बेशक

इस मैन्युअल रूप से लिखने के लिए मामूली बात है अगर तुम नहीं करते सज्जाकार पर भरोसा करना चाहते हैं: ऊपर

import trackHierarchy from './hierarachy-tracked'; 

export class Animal { } 

class Snake extends Animal { ... } 
trackHierarchy(Snake); 

export {Snake}; 

अपने उदाहरण कोड पर वापस, यह आसानी से हासिल किया जाता है।

यह

var childTypes = assembly.GetTypes().Where(_ => _.IsSubclassOf(typeof(Animal))); 

से चला जाता है बस

const childClasses = Animal.extendedBy || []; 

एक चेतावनी

का वचन आप पाते हैं अपने आप को इस तरह कोड लिखने के लिए इच्छुक हैं, तो आप एक कदम पीछे ले जाना चाहिए करने के लिए और सुनिश्चित करें कि आप वास्तव में जावास्क्रिप्ट जानते हैं। इस तरह के पैटर्न, और वास्तव में आपका उदाहरण उपयोग केस, आमतौर पर इंगित करता है कि कोई शास्त्रीय मानसिकता के साथ भाषा में आया है, ईएस 2015 कक्षाओं को देखा है, और यह सोचने लगा कि वे पारंपरिक भाषाओं में कक्षाओं से संबंधित हैं।

ईएस कक्षाएं सी #, सी ++, जावा, या स्कैला कक्षाओं की तरह कम नहीं हो सकतीं।

पहला और सबसे महत्वपूर्ण: जावास्क्रिप्ट में कक्षाएं प्रकार नहीं हैं।

जावास्क्रिप्ट में कक्षाएं मान हैं।

उनका घोषणा फॉर्म मूल रूप से प्रोटोटाइप पर एक वाक्य रचनात्मक चीनी है। जिस पैटर्न को आप प्राप्त करने की कोशिश कर रहे हैं, वह सुझाव देता है कि आप इसे अच्छी तरह से समझ नहीं सकते हैं। विशेष रूप से, यह सुझाव देता है कि आप सोच सकते हैं कि वे विशेष हैं।

+0

यह अभी भी बेबेल 7 में काम करता है, यहां तक ​​कि सजावटी लोगों के बड़े बदलावों के साथ भी। बेशक अगर आप सुरक्षित पक्ष में रहना चाहते हैं, तो आप केवल फ़ंक्शन फॉर्म का उपयोग करेंगे –

संबंधित मुद्दे