यह कुछ अलग तरीके दिखाने के लिए इस पर कुछ त्वरित शॉट्स हैं। वे किसी भी तरह से "पूर्ण" नहीं हैं और एक अस्वीकरण के रूप में, मुझे नहीं लगता कि यह ऐसा करना एक अच्छा विचार है। इसके अलावा कोड बहुत साफ नहीं है क्योंकि मैंने इसे जल्दी से एक साथ टाइप किया था।
नोट के रूप में भी: निश्चित रूप से डिसेरिएबल क्लासेस के लिए डिफॉल्ट कंस्ट्रक्टर की आवश्यकता होती है जैसा कि अन्य सभी भाषाओं में होता है, जहाँ मुझे किसी भी तरह के डीरियलाइज़ेशन की जानकारी है। बेशक, अगर आप बिना किसी तर्क के एक गैर-डिफ़ॉल्ट निर्माता को कॉल करते हैं, तो जावास्क्रिप्ट शिकायत नहीं करेगा, लेकिन कक्षा को इसके लिए बेहतर तैयार किया जाएगा (इसके अलावा, यह वास्तव में "टाइपस्क्रिप्ट तरीका" नहीं होगा)।
विकल्प # 1: कोई रन-टाइम जानकारी बिल्कुल नहीं
इस दृष्टिकोण के साथ समस्या यह है कि किसी भी सदस्य का नाम उसकी कक्षा से मेल खाना चाहिए। जो स्वचालित रूप से आपको प्रति वर्ग एक ही प्रकार के एक सदस्य तक सीमित करता है और अच्छे अभ्यास के कई नियमों को तोड़ता है। मैं इसके खिलाफ दृढ़ता से सलाह देता हूं, लेकिन बस इसे यहां सूचीबद्ध करें क्योंकि यह पहला "मसौदा" था जब मैंने यह उत्तर लिखा था (यह भी कि नाम "फू" आदि क्यों हैं)।
module Environment {
export class Sub {
id: number;
}
export class Foo {
baz: number;
Sub: Sub;
}
}
function deserialize(json, environment, clazz) {
var instance = new clazz();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], environment, environment[prop]);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
baz: 42,
Sub: {
id: 1337
}
};
var instance = deserialize(json, Environment, Environment.Foo);
console.log(instance);
विकल्प # 2: नाम संपत्ति
विकल्प # 1 में समस्या से छुटकारा पाने के लिए, हमें इस बात की कुछ जानकारी होनी चाहिए कि JSON ऑब्जेक्ट में नोड किस प्रकार का है। समस्या यह है कि टाइपस्क्रिप्ट में, ये चीजें संकलन-समय के निर्माण हैं और हमें रनटाइम पर उनकी आवश्यकता है - लेकिन रनटाइम ऑब्जेक्ट्स को बस सेट होने तक उनके गुणों के बारे में कोई जानकारी नहीं होती है।
ऐसा करने का एक तरीका वर्गों को उनके नामों से अवगत कराना है। हालांकि आपको JSON में भी इस संपत्ति की आवश्यकता है। वास्तव में, आपको केवल इसे जसन में चाहिए:
module Environment {
export class Member {
private __name__ = "Member";
id: number;
}
export class ExampleClass {
private __name__ = "ExampleClass";
mainId: number;
firstMember: Member;
secondMember: Member;
}
}
function deserialize(json, environment) {
var instance = new environment[json.__name__]();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], environment);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
__name__: "ExampleClass",
mainId: 42,
firstMember: {
__name__: "Member",
id: 1337
},
secondMember: {
__name__: "Member",
id: -1
}
};
var instance = deserialize(json, Environment);
console.log(instance);
विकल्प # 3: स्पष्ट रूप से सदस्य प्रकार बताते हुए
जैसा कि ऊपर कहा गया है, वर्ग सदस्यों की प्रकार की जानकारी रनटाइम पर उपलब्ध नहीं है - जब तक कि हम इसे उपलब्ध नहीं कराते हैं। हमें केवल गैर-आदिम सदस्यों के लिए ऐसा करने की आवश्यकता है और हम जाने के लिए अच्छे हैं:
interface Deserializable {
getTypes(): Object;
}
class Member implements Deserializable {
id: number;
getTypes() {
// since the only member, id, is primitive, we don't need to
// return anything here
return {};
}
}
class ExampleClass implements Deserializable {
mainId: number;
firstMember: Member;
secondMember: Member;
getTypes() {
return {
// this is the duplication so that we have
// run-time type information :/
firstMember: Member,
secondMember: Member
};
}
}
function deserialize(json, clazz) {
var instance = new clazz(),
types = instance.getTypes();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], types[prop]);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
mainId: 42,
firstMember: {
id: 1337
},
secondMember: {
id: -1
}
};
var instance = deserialize(json, ExampleClass);
console.log(instance);
विकल्प # 4: क्रिया, लेकिन साफ-सुथरा तरीका
अपडेट 01/03/2016: जैसा कि @GameAlchemist ने टिप्पणियों ( विचार , कार्यान्वयन) में बताया ) टाइपस्क्रिप्ट 1.7 के रूप में, नीचे वर्णित समाधान को क्लास / प्रॉपर्टी डेकोरेटर्स का उपयोग करके बेहतर तरीके से लिखा जा सकता है।
सीरियलाइजेशन हमेशा एक समस्या है और मेरी राय में, सबसे अच्छा तरीका एक तरीका है जो सिर्फ सबसे छोटा नहीं है। सभी विकल्पों में से, यह वही है जो मैं पसंद करूंगा क्योंकि वर्ग के लेखक का वांछित वस्तुओं की स्थिति पर पूर्ण नियंत्रण है। अगर मुझे अनुमान लगाना था, तो मैं कहूंगा कि अन्य सभी विकल्प, जल्दी या बाद में, आपको परेशानी में डाल देंगे (जब तक कि जावास्क्रिप्ट इस से निपटने के लिए एक देशी तरीका नहीं आता है)।
वास्तव में, निम्न उदाहरण लचीलापन न्याय नहीं करता है। यह वास्तव में सिर्फ कक्षा की संरचना की नकल करता है। हालांकि, यहां आपको जो अंतर रखना है, वह यह है कि किसी भी प्रकार के JSON का उपयोग करने के लिए वर्ग का पूर्ण नियंत्रण है, यह संपूर्ण कक्षा की स्थिति को नियंत्रित करना चाहता है (आप चीजों की गणना कर सकते हैं आदि)।
interface Serializable<T> {
deserialize(input: Object): T;
}
class Member implements Serializable<Member> {
id: number;
deserialize(input) {
this.id = input.id;
return this;
}
}
class ExampleClass implements Serializable<ExampleClass> {
mainId: number;
firstMember: Member;
secondMember: Member;
deserialize(input) {
this.mainId = input.mainId;
this.firstMember = new Member().deserialize(input.firstMember);
this.secondMember = new Member().deserialize(input.secondMember);
return this;
}
}
var json = {
mainId: 42,
firstMember: {
id: 1337
},
secondMember: {
id: -1
}
};
var instance = new ExampleClass().deserialize(json);
console.log(instance);