আমি কীভাবে কোনও JSON অবজেক্টের সাথে টাইপস্ক্রিপ্ট অবজেক্টটি সূচনা করব


198

আমি একটি এএসএক্স কল থেকে একটি REST সার্ভারে একটি JSON অবজেক্ট পেয়েছি। এই অবজেক্টটির এমন সম্পত্তির নাম রয়েছে যা আমার টাইপস্ক্রিপ্টের ক্লাসের সাথে মেলে (এটি এই প্রশ্নের একটি ফলো-অন )।

এটি আরম্ভ করার সর্বোত্তম উপায় কী? আমি মনে করি না এই কাজ করবে কারণ শ্রেণী (ও JSON বস্তু) সদস্যরা বস্তু এবং সদস্যরা শ্রেণীর হয় তালিকা আছে, এবং যারা শ্রেণীর সদস্যরা তালিকা এবং / অথবা ক্লাস আছে।

তবে আমি এমন একটি দৃষ্টিভঙ্গি পছন্দ করব যা সদস্যের নামগুলি সন্ধান করবে এবং তাদের জুড়ে নির্দিষ্ট করে দেবে, প্রয়োজনীয় তালিকা তৈরি করবে এবং তাত্ক্ষণিক ক্লাস তৈরি করবে, তাই আমাকে প্রতিটি শ্রেণীর প্রত্যেক সদস্যের জন্য স্পষ্ট কোড লিখতে হবে না (অনেক আছে!)


1
আপনি কেন এটি আবার জিজ্ঞাসা করলেন (আমি অন্য প্রশ্নের জবাব হিসাবে বলেছি এটি কাজ করবে না এবং এটি বিদ্যমান বস্তুতে সম্পত্তি অনুলিপি করার বিষয়ে ছিল)?
ওয়্যার্ডপ্রাইরি


3
@ ওয়্যার্ডপ্রাইরি এই প্রশ্নটি আলাদা, এটি জিজ্ঞাসা করছে যে আমি সম্পত্তিগুলি একের পর এক চালাতে পারি এবং সেগুলি সরিয়ে দিতে পারি কিনা। অন্যান্য প্রশ্নগুলি জিজ্ঞাসা করছিল যে আমি এটি castালতে পারি কিনা।
ডেভিড থিলেন

1
@ ওয়্যার্ডপ্রেইরি কনট: আপনি যদি প্রাথমিক প্রকারভেদে না যাওয়া পর্যন্ত আপনি যদি সম্পত্তিগুলিতে ডাইভিং চালিয়ে যান, তবে সেগুলি নির্ধারিত হতে পারে।
ডেভিড থিলেন

2
এটি এখনও আপনার সমস্ত মূল্যবোধের অনুলিপি করছে যেমনটি আমি পরামর্শ দিয়েছিলাম যে আপনার করা দরকার। এটি টাইপস্ক্রিপ্টে করার নতুন কোনও উপায় নেই কারণ এটি জাভাস্ক্রিপ্টের একটি মৌলিক নকশা। বড় অবজেক্টগুলির জন্য, আপনি কোনও মান অনুলিপি করতে চান না এবং পরিবর্তে ডেটা স্ট্রাকচারটি "কাজ" করতে পারেন।
ওয়্যার্ডপ্রাইরি

উত্তর:


188

কয়েকটি ভিন্ন উপায় দেখানোর জন্য এগুলিতে কিছু দ্রুত শট sh এগুলি কোনওভাবেই "সম্পূর্ণ" নয় এবং অস্বীকৃতি হিসাবে, আমার মনে হয় না এটি এটি করা ভাল ধারণা। কোডটি খুব বেশি পরিষ্কার নয় যেহেতু আমি কেবল এটির সাথে দ্রুত টাইপ করেছি।

এছাড়াও একটি নোট হিসাবে: অবশ্যই deserializable শ্রেণীর ডিফল্ট নির্মাতাদের যেমন প্রয়োজন হয় অন্য সমস্ত ভাষায় যেখানে আমি যে কোনও ধরণের deserialization সম্পর্কে সচেতন। অবশ্যই জাভাস্ক্রিপ্ট অভিযোগ করবে না যদি আপনি কোনও যুক্তি ছাড়াই অ-ডিফল্ট নির্মাতাকে কল করেন তবে ক্লাসটি তার জন্য আরও ভাল প্রস্তুত থাকুন (প্লাস, এটি আসলে "টাইপস্ক্রিপি উপায়" হবে না)।

বিকল্প # 1: কোনও রান-টাইম তথ্য নেই

এই পদ্ধতির সমস্যাটি বেশিরভাগ ক্ষেত্রে যে কোনও সদস্যের নাম অবশ্যই তার শ্রেণীর সাথে মেলে। যা স্বয়ংক্রিয়ভাবে আপনাকে প্রতি ক্লাসে একই ধরণের এক সদস্যের মধ্যে সীমাবদ্ধ করে দেয় এবং ভাল অনুশীলনের বেশ কয়েকটি নিয়ম ভঙ্গ করে। আমি এর বিরুদ্ধে দৃ strongly়ভাবে পরামর্শ দিচ্ছি, তবে কেবল এটি এখানে তালিকাবদ্ধ করুন কারণ যখন আমি এই উত্তরটি লিখি তখন এটিই প্রথম "খসড়া" ছিল (যার কারণেই নামগুলি "ফু" ইত্যাদি)।

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 আপডেট করুন: যেমন @ গেমএলচেমিস্ট মন্তব্যগুলিতে ( ধারণা , বাস্তবায়ন ) ইঙ্গিত করেছেন, টাইপস্ক্রিপ্ট ১.7 অনুসারে, নীচে বর্ণিত সমাধানটি শ্রেণি / সম্পত্তি সাজসজ্জার ব্যবহার করে আরও ভালভাবে লেখা যেতে পারে।

সিরিয়ালাইজেশন সর্বদা একটি সমস্যা এবং আমার মতে, সবচেয়ে ভাল উপায় একটি উপায় যা কেবল সবচেয়ে কম নয়। সমস্ত অপশনগুলির মধ্যে, আমি এটিই পছন্দ করব কারণ শ্রেণীর লেখকের ডিসরিয়ালাইজড অবজেক্টগুলির রাজ্যের সম্পূর্ণ নিয়ন্ত্রণ রয়েছে। যদি আমার অনুমান করতে হয় তবে আমি বলব যে তাড়াতাড়ি বা পরে অন্যান্য সমস্ত অপশন আপনাকে সমস্যায় ফেলবে (যতক্ষণ না জাভাস্ক্রিপ্ট এগুলি মোকাবেলার জন্য একটি স্থানীয় উপায় নিয়ে আসে)।

সত্যই, নিম্নলিখিত উদাহরণটি নমনীয়তা ন্যায়বিচার করে না। এটি সত্যই ক্লাসের কাঠামোটি অনুলিপি করে। এখানে আপনার যে পার্থক্যটি মনে রাখতে হবে তা হ'ল ক্লাসটির যে কোনও ধরণের জেএসওএন ব্যবহার করার সম্পূর্ণ নিয়ন্ত্রণ রয়েছে যা এটি পুরো বর্গের অবস্থা নিয়ন্ত্রণ করতে চায় (আপনি জিনিসগুলি গণনা করতে পারেন))

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);

12
বিকল্প # 4 হ'ল আমি যেতে যুক্তিসঙ্গত উপায় কল করব। আপনার এখনও ডিসরিয়ালাইজেশন কোডটি লিখতে হবে তবে এটি একই শ্রেণিতে এবং সম্পূর্ণ নিয়ন্ত্রণযোগ্য la আপনি যদি জাভা থেকে আগত হন তবে এটি লেখার জন্য equalsবা toStringপদ্ধতিগুলির সাথে তুলনাযোগ্য (কেবলমাত্র আপনি সাধারণত সেগুলি স্বয়ংক্রিয়ভাবে উত্পন্ন করেছেন)। আপনি চাইলে এর জন্য জেনারেটর লেখা খুব কঠিন হওয়া উচিত নয় deserializeতবে এটি কেবল রান-টাইম অটোমেশন হতে পারে না।
ইনগো বার্ক

2
@ ইনগোবার্ক, আমি জানি আমি 2 বছর পরে এই প্রশ্নটি জিজ্ঞাসা করছি তবে কীভাবে এটি বস্তুর অ্যারেতে কাজ করবে? উপরের নমুনা কোডটি JSON অবজেক্টের জন্য সূক্ষ্মভাবে কাজ করে। কীভাবে এটি বস্তুর অ্যারে ব্যবহার করা যেতে পারে?
প্রতীক গায়কওয়াদ

2
এক পক্ষের মন্তব্য: ১.7 থেকে (স্বীকার করা আপনার উত্তরের তুলনায় আরও সাম্প্রতিক), টাইপস্ক্রিপ্ট শ্রেণি / সম্পত্তি সজ্জা প্রদান করে যা চতুর্থ সমাধানটি আরও সুস্পষ্ট উপায়ে লিখতে দেয়।
গেমএলকেমিস্ট

1
: সেরা ডকুমেন্টেশন আমি পাওয়া Stackoverflow উত্তর stackoverflow.com/a/29837695/856501 । আমি আমার একটি প্রকল্পে সজ্জা ব্যবহার করেছি, এবং যদিও আমি কয়েকটি অন্যান্য বৈশিষ্ট্য চাই তবে আমাকে বলতে হবে তারা একটি কবজির মতো কাজ করে।
গেমএলচেমিস্ট

2
আমি এখনও কোনও প্রযোজনা প্রকল্পের জন্য সজ্জকারগুলিতে ঝাঁপ দেব না - মনে রাখবেন তারা এখনও পরীক্ষামূলক বৈশিষ্ট্য। আমি "পরীক্ষাগুলি" তে রিয়েল-ওয়ার্ল্ড কোডটি ভিত্তি করব না কারণ যতদূর আমরা উদ্বিগ্ন তারা পরবর্তী সংস্করণে চলে যেতে পারে এবং আপনাকে কোডের একটি গুচ্ছ পুনর্লিখন করতে হবে বা একটি পুরানো টিএস সংস্করণে চিরতরে আটকে থাকতে হবে। কেবল আমার 0 .02
আরভিপি

35

আপনি ব্যবহার করতে পারেন Object.assignআমি কখন এটি যুক্ত হয়েছিল জানি না, আমি বর্তমানে টাইপস্ক্রিপ্ট 2.0.2 ব্যবহার করছি এবং এটি ES6 বৈশিষ্ট্য হিসাবে উপস্থিত হবে।

client.fetch( '' ).then( response => {
        return response.json();
    } ).then( json => {
        let hal : HalJson = Object.assign( new HalJson(), json );
        log.debug( "json", hal );

এখানে HalJson

export class HalJson {
    _links: HalLinks;
}

export class HalLinks implements Links {
}

export interface Links {
    readonly [text: string]: Link;
}

export interface Link {
    readonly href: URL;
}

ক্রোম যা বলে তা এখানে

HalJson {_links: Object}
_links
:
Object
public
:
Object
href
:
"http://localhost:9000/v0/public

যাতে আপনি দেখতে পান এটি পুনরাবৃত্তভাবে অ্যাসাইনটি করে না


2
তাই, মূলত, এটা এই আছে: Object.assign। আমাদের কাছে এর পরে এই দুটিটির উপরে দুটি অভিধানের মতো উত্তর রয়েছে কেন?
phil294

18
@ ব্লাউহিম কারণ Object.assignপুনরাবৃত্তির সাথে কাজ করবে না এবং সঠিক বস্তুর প্রকারকে তাত্পর্য হিসাবে দেখবে না, Objectউদাহরণগুলিকে মান হিসাবে ছেড়ে যায় । তুচ্ছ কাজের জন্য এটি সূক্ষ্ম হলেও, জটিল ধরণের সিরিয়ালাইজেশন এটি দিয়ে সম্ভব নয়। উদাহরণস্বরূপ, যদি কোনও শ্রেণীর সম্পত্তি কাস্টম শ্রেণীর ধরণের হয় তবে JSON.parse+ Object.assignসম্পত্তিটি তত্ক্ষণাতিত করে Object। পার্শ্ব প্রতিক্রিয়া অন্তর্ভুক্ত পদ্ধতি এবং অ্যাক্সেসর অন্তর্ভুক্ত।
জন ওয়েইজ

@ জোহান ওয়েইজ অবজেক্টের শীর্ষ স্তরের শ্রেণীর ক্ষেত্রে সঠিক ধরণ রয়েছে এবং আমি এতে পুনরাবৃত্তির বিষয়টি উল্লেখ করেছি ... এতে বলা হয়েছে, ওয়াইএমএমভি, এবং সেগুলি ডিল ভঙ্গকারী হতে পারে।
xenoterracide

প্রশ্ন থেকে সরাসরি উদ্ধৃত: "ক্লাসে এমন সদস্য রয়েছে যা অবজেক্ট এবং সদস্যদের তালিকা যা শ্রেণি, এবং সেই ক্লাসে এমন সদস্য রয়েছে যেগুলি তালিকা এবং / অথবা ক্লাস রয়েছে [...] আমি সদস্যকে সন্ধান করা এমন একটি পদ্ধতির পছন্দ করব নাম এবং তাদের জুড়ে নিয়োগ, তালিকা তৈরি করা এবং প্রয়োজনীয় ক্লাস ইনস্ট্যান্ট করা, সুতরাং আমাকে প্রতিটি শ্রেণীর প্রত্যেক সদস্যের জন্য সুস্পষ্ট কোড লিখতে হবে না " - যা এর ক্ষেত্রে নয় isObject.assign , যেখানে এখনও নেস্টেড ইনস্ট্যান্টেশন লিখতে নেমে আসে হাত. এই পদ্ধতির খুব সহজ, টিউটোরিয়াল-স্তরের অবজেক্টের জন্য ভাল, তবে বাস্তব ব্যবহারের জন্য নয়।
জন ওয়েইজ

@ জন ওয়েইজ নিশ্চিত, বেশিরভাগই এর সাথে উত্তর দিয়েছিল কারণ এটি কোনও উত্তরে ছিল না এবং কিছু ব্যবহারের ক্ষেত্রে সহজ বলে মনে হয়েছিল। আমি নিশ্চিত যে এটি আপনি যা খুঁজছেন তা করার জন্য প্রতিবিম্বের মতো অন্যান্য উত্তরের সাথে সংমিশ্রণেও ব্যবহার করা যেতে পারে। আমি এটিও কিছু অংশে লিখেছিলাম যাতে আমি এটি পরে মনে রাখতে পারি। এই উত্তরগুলি দেখে এবং সেখানে আরও শক্তিশালী লাইব্রেরি ব্যবহার করা এবং লিখে রাখা "সত্যিকারের ব্যবহার" এর জন্য উপলব্ধ কিছু বলে মনে হয় না।
xenoterracide

34

টিএলডিআর: টাইপড জেএসওএন (ধারণার কার্যকারী প্রমাণ)


এই সমস্যার জটিলতার মূলটি হ'ল রান টাইমের সময় আমাদের কেবলমাত্র সংকলনের সময় বিদ্যমান টাইপ তথ্য ব্যবহার করে জেএসএনকে ডিসিজায়ালাইজ করা দরকার । এর জন্য প্রয়োজন টাইপ-তথ্য একরকম রানটাইম এ উপলব্ধ করা হয়।

সৌভাগ্যক্রমে, এটি সজ্জক এবং প্রতিবিম্বিতকারকগুলির দ্বারা খুব মার্জিত এবং শক্তিশালী উপায়ে সমাধান করা যেতে পারে :

  1. মেটাডেটা তথ্য রেকর্ড করতে এবং কোথাও সেই তথ্য সংরক্ষণ করতে, বৈশিষ্ট্যগুলিতে সিরিয়ালাইজেশন সাবলীল বৈশিষ্ট্যগুলিতে সম্পত্তি সজ্জা ব্যবহার করুন, উদাহরণস্বরূপ ক্লাস প্রোটোটাইপে
  2. একটি পুনরাবৃত্ত ইনিশিয়েলাইজারকে (ডিসরিয়ালাইজার) এই মেটাডেটা তথ্য ফিড করুন

 

রেকর্ডিং টাইপ-তথ্য

রিফ্লেক্টেকটর এবং সম্পত্তি সজ্জকারের সংমিশ্রণের সাথে, কোনও সম্পত্তি সম্পর্কে প্রকারের তথ্য সহজেই রেকর্ড করা যায়। এই পদ্ধতির একটি প্রাথমিক বাস্তবায়ন হবে:

function JsonMember(target: any, propertyKey: string) {
    var metadataFieldKey = "__propertyTypes__";

    // Get the already recorded type-information from target, or create
    // empty object if this is the first property.
    var propertyTypes = target[metadataFieldKey] || (target[metadataFieldKey] = {});

    // Get the constructor reference of the current property.
    // This is provided by TypeScript, built-in (make sure to enable emit
    // decorator metadata).
    propertyTypes[propertyKey] = Reflect.getMetadata("design:type", target, propertyKey);
}

প্রদত্ত যে কোনও সম্পত্তির জন্য, উপরের স্নিপেট __propertyTypes__শ্রেণীর প্রোটোটাইপের গোপন সম্পত্তিতে সম্পত্তিটির কনস্ট্রাক্টর ফাংশনের একটি উল্লেখ যুক্ত করবে । উদাহরণ স্বরূপ:

class Language {
    @JsonMember // String
    name: string;

    @JsonMember// Number
    level: number;
}

class Person {
    @JsonMember // String
    name: string;

    @JsonMember// Language
    language: Language;
}

এবং এটি হ'ল রানটাইমের সময় আমাদের কাছে প্রয়োজনীয় টাইপ-তথ্য রয়েছে, যা এখন প্রক্রিয়া করা যায়।

 

প্রক্রিয়াকরণ প্রকারের তথ্য

আমাদের প্রথমে একটি প্রাপ্ত করা দরকার Object উদাহরণটিJSON.parse - এর পরে, আমরা __propertyTypes__(উপরে সংগ্রহ করা) এন্টিয়ারগুলি নিয়ে পুনরাবৃত্তি করতে পারি এবং সেই অনুযায়ী প্রয়োজনীয় বৈশিষ্ট্যগুলি ইনস্ট্যান্ট করতে পারি। মূল অবজেক্টের ধরণ অবশ্যই নির্দিষ্ট করতে হবে, যাতে ডিসরিয়ালাইজারের একটি সূচনা-পয়েন্ট থাকে।

আবার, এই পদ্ধতির একটি মৃত সহজ প্রয়োগ হবে:

function deserialize<T>(jsonObject: any, Constructor: { new (): T }): T {
    if (!Constructor || !Constructor.prototype.__propertyTypes__ || !jsonObject || typeof jsonObject !== "object") {
        // No root-type with usable type-information is available.
        return jsonObject;
    }

    // Create an instance of root-type.
    var instance: any = new Constructor();

    // For each property marked with @JsonMember, do...
    Object.keys(Constructor.prototype.__propertyTypes__).forEach(propertyKey => {
        var PropertyType = Constructor.prototype.__propertyTypes__[propertyKey];

        // Deserialize recursively, treat property type as root-type.
        instance[propertyKey] = deserialize(jsonObject[propertyKey], PropertyType);
    });

    return instance;
}
var json = '{ "name": "John Doe", "language": { "name": "en", "level": 5 } }';
var person: Person = deserialize(JSON.parse(json), Person);

উপরের ধারণাটি জেএসএনে উপস্থিত রয়েছে তার পরিবর্তে প্রত্যাশিত ধরণের (জটিল / অবজেক্ট মানের জন্য) ডিসরিয়ালাইজেশনের একটি বড় সুবিধা রয়েছে । যদি একটি Personপ্রত্যাশিত হয়, তবে এটি তৈরি করা একটি Personউদাহরণ। আদিম ধরণের এবং অ্যারেগুলির জন্য কিছু অতিরিক্ত সুরক্ষা ব্যবস্থা সহ, এই পদ্ধতিকে সুরক্ষিত করা যেতে পারে, যা প্রতিরোধ করে কোনও দূষিত জেএসওএনকে ।

 

এজ কেস

যাইহোক, যদি আপনি এখন খুশি যে সমাধান হয় যে সহজ, আমি কিছু দুঃসংবাদ আছে: একটি আছে সুবিশাল প্রান্ত মামলা যত্ন গ্রহণ করা প্রয়োজন সংখ্যা। যার মধ্যে কয়েকটি হ'ল:

  • অ্যারে এবং অ্যারে উপাদানগুলি (বিশেষত নেস্টেড অ্যারেগুলিতে)
  • পলিমরফিজ্ম
  • বিমূর্ত ক্লাস এবং ইন্টারফেস
  • ...

আপনি যদি এই সমস্তগুলি নিয়ে ঘাঁটাঘাঁটি করতে চান না (আমি বাজি ধরছি যে আপনি করবেন না), আমি এই পদ্ধতির ব্যবহার করে একটি প্রুফ অফ কনসেপ্টের একটি কার্যকরী পরীক্ষামূলক সংস্করণের সুপারিশ করতে পেরে খুশি হব, টাইপডজসন - যা আমি তৈরি করেছি এই সঠিক সমস্যাটি মোকাবেলা করার জন্য, আমি প্রতিদিন নিজেকে এই সমস্যার মুখোমুখি করি।

কীভাবে সজ্জিতকারীদের এখনও পরীক্ষামূলক হিসাবে বিবেচনা করা হচ্ছে, এর কারণে আমি এটিকে উত্পাদন ব্যবহারের জন্য ব্যবহারের পরামর্শ দেব না, তবে এখনও পর্যন্ত এটি আমার ভাল ব্যবহার করেছে।


TypedJSON দুর্দান্ত কাজ করেছে; রেফারেন্সের জন্য অনেক ধন্যবাদ।
নীল

দুর্দান্ত কাজ, আপনি একটি সমস্যার জন্য খুব মার্জিত সমাধান নিয়ে এসেছেন যা আমাকে কিছু সময়ের জন্য কষ্ট দিচ্ছে। আমি আপনার প্রকল্প খুব কাছাকাছি অনুসরণ করা হবে!
জন স্ট্রিকলার

12

আমি এই লোকটিকে কাজটি করতে ব্যবহার করছি: https://github.com/weichx/cerialize

এটি অত্যন্ত সাধারণ তবে শক্তিশালী। এটি সমর্থন করে:

  • বস্তুগুলির একটি সম্পূর্ণ গাছের ক্রমিকায়ন এবং deserialization।
  • একই বস্তুর উপর স্থায়ী এবং ক্ষণস্থায়ী বৈশিষ্ট্য।
  • (ডি) সিরিয়ালাইজেশন যুক্তি কাস্টমাইজ করতে হুকস।
  • এটি (ডি) একটি বিদ্যমান উদাহরণে সিরিয়ালাইজ করতে পারে (কৌণিকের জন্য দুর্দান্ত) বা নতুন উদাহরণ তৈরি করতে পারে।
  • প্রভৃতি

উদাহরণ:

class Tree {
  @deserialize public species : string; 
  @deserializeAs(Leaf) public leafs : Array<Leaf>;  //arrays do not need extra specifications, just a type.
  @deserializeAs(Bark, 'barkType') public bark : Bark;  //using custom type and custom key name
  @deserializeIndexable(Leaf) public leafMap : {[idx : string] : Leaf}; //use an object as a map
}

class Leaf {
  @deserialize public color : string;
  @deserialize public blooming : boolean;
  @deserializeAs(Date) public bloomedAt : Date;
}

class Bark {
  @deserialize roughness : number;
}

var json = {
  species: 'Oak',
  barkType: { roughness: 1 },
  leafs: [ {color: 'red', blooming: false, bloomedAt: 'Mon Dec 07 2015 11:48:20 GMT-0500 (EST)' } ],
  leafMap: { type1: { some leaf data }, type2: { some leaf data } }
}
var tree: Tree = Deserialize(json, Tree);

6

আমি একটি সরঞ্জাম তৈরি করেছি যা টাইপস্ক্রিপ্ট ইন্টারফেস এবং একটি রানটাইম "টাইপ মানচিত্র" উত্পন্ন করে ফলাফলের বিরুদ্ধে রানটাইম টাইপচেকিংয়ের জন্য JSON.parse: ts.quicktype.io

উদাহরণস্বরূপ, এই JSON দেওয়া:

{
  "name": "David",
  "pets": [
    {
      "name": "Smoochie",
      "species": "rhino"
    }
  ]
}

কুইকটাইপ নিম্নলিখিত টাইপস্ক্রিপ্ট ইন্টারফেস এবং টাইপ ম্যাপ উত্পাদন করে:

export interface Person {
    name: string;
    pets: Pet[];
}

export interface Pet {
    name:    string;
    species: string;
}

const typeMap: any = {
    Person: {
        name: "string",
        pets: array(object("Pet")),
    },
    Pet: {
        name: "string",
        species: "string",
    },
};

তারপরে আমরা JSON.parseটাইপ ম্যাপের বিপরীতে ফলাফলটি যাচাই করি :

export function fromJson(json: string): Person {
    return cast(JSON.parse(json), object("Person"));
}

আমি কিছু কোড রেখেছি , তবে আপনি বিশদটির জন্য দ্রুত টাইপ করতে পারেন ।


1
কয়েক ঘন্টা গবেষণা করার পরে এবং কয়েকটি পার্সিং কৌশলগুলিতে আমার হাত চেষ্টা করার পরে, আমি এটি বলতে পারি এটি একটি দুর্দান্ত সমাধান - মূলত কারণ সজ্জকরা এখনও পরীক্ষামূলক। * মূল লিঙ্কটি আমার জন্য নষ্ট হয়ে গেছে; তবে ts.quicktype.io কাজ করে। * জেএসএনকে জেএসওন স্কিমাতে রূপান্তর করা প্রথম ধাপ is
LexieHankins

3

বিকল্প # 5: টাইপস্ক্রিপ্ট কনস্ট্রাক্টর এবং jQuery.extend ব্যবহার করে

এটি সর্বাধিক রক্ষণাবেক্ষণযোগ্য পদ্ধতি বলে মনে হচ্ছে: একটি কনস্ট্রাক্টর যুক্ত করুন যা জেসন কাঠামো হিসাবে প্যারামিটার হিসাবে নেয় এবং জসন অবজেক্টকে প্রসারিত করে। এইভাবে আপনি একটি জসন কাঠামো পুরো অ্যাপ্লিকেশন মডেলটিতে পার্স করতে পারেন।

কনস্ট্রাক্টরটিতে ইন্টারফেস বা তালিকা বৈশিষ্ট্য তৈরি করার দরকার নেই।

export class Company
{
    Employees : Employee[];

    constructor( jsonData: any )
    {
        jQuery.extend( this, jsonData);

        // apply the same principle to linked objects:
        if ( jsonData.Employees )
            this.Employees = jQuery.map( jsonData.Employees , (emp) => {
                return new Employee ( emp );  });
    }

    calculateSalaries() : void { .... }
}

export class Employee
{
    name: string;
    salary: number;
    city: string;

    constructor( jsonData: any )
    {
        jQuery.extend( this, jsonData);

        // case where your object's property does not match the json's:
        this.city = jsonData.town;
    }
}

আপনার এজাক্স কলব্যাকে যেখানে আপনি বেতন গণনা করার জন্য একটি সংস্থা পান:

onReceiveCompany( jsonCompany : any ) 
{
   let newCompany = new Company( jsonCompany );

   // call the methods on your newCompany object ...
   newCompany.calculateSalaries()
}

যেখানে $.extendথেকে এসেছে?
তিমি_সামগ্রী

@ তিমি_সামগ্রী আমি ধরে নেব লেখক jQuery লাইব্রেরি উল্লেখ করছেন। জাভাস্ক্রিপ্ট বিশ্বে, '$' প্রায়শই কেউ jQuery ব্যবহার করে।
নিক রথ

কিভাবে এটি আমদানি? এটি কেবল এইচটিএমএল মাথায় অন্তর্ভুক্ত করা যথেষ্ট?
তিমি_সামগ্রী

হ্যাঁ আমি jQuery দ্বারা replace প্রতিস্থাপনের উত্তর আপডেট করি। এইচটিএমএল শিরোনামে jQuery.js আমদানি করুন এবং আপনার প্যাকেজ.জসন, ডিভিনিডেনপেন্সি বিভাগে @ প্রকার / jquery ইনস্টল করুন এবং যুক্ত করুন।
অ্যান্টনি ব্রেনেলিয়ার

1
নোট করুন যে জাভাস্ক্রিপ্টে আপনার করা উচিত Object.assign, যা jQuery এর এই নির্ভরতা সরিয়ে দেয়।
লিয়ন পেলেটিয়ার

2

সাধারণ বস্তুর জন্য, আমি এই পদ্ধতিটি পছন্দ করি:

class Person {
  constructor(
    public id: String, 
    public name: String, 
    public title: String) {};

  static deserialize(input:any): Person {
    return new Person(input.id, input.name, input.title);
  }
}

var person = Person.deserialize({id: 'P123', name: 'Bob', title: 'Mr'});

কনস্ট্রাক্টরের বৈশিষ্ট্যগুলি সংজ্ঞায়িত করার দক্ষতা অর্জন করে এটি সংক্ষিপ্ত হতে দেয় be

এটি আপনাকে একটি টাইপ করা অবজেক্ট (সমস্ত উত্তর বনাম যা অবজেক্ট.অ্যাসাইন বা কিছু বৈকল্পিক ব্যবহার করে, যা আপনাকে একটি বস্তু দেয়) পায় এবং বাহ্যিক গ্রন্থাগার বা সজ্জকার প্রয়োজন হয় না।


1

উপরোক্ত বর্ণিত ৪ র্থ বিকল্পটি এটি করার একটি সহজ এবং দুর্দান্ত উপায়, যা আপনাকে দ্বিতীয় শ্রেণীর সাথে একত্রে করতে হবে যেখানে শ্রেণি শ্রেণিবিন্যাস পরিচালনা করতে হবে যেমন উদাহরণস্বরূপ সদস্য তালিকা যা কোনও সাবক্লাসের উপস্থিতিগুলির কোনও যেমন একজন সদস্য সুপার ক্লাস, যেমন পরিচালক সদস্য বা ছাত্রকে সদস্য বাড়ায়। সেক্ষেত্রে আপনাকে জেসন ফর্ম্যাটে সাবক্লাস টাইপ দিতে হবে


1

JQuery। প্রসারিত আপনার জন্য এটি করে:

var mytsobject = new mytsobject();

var newObj = {a:1,b:2};

$.extend(mytsobject, newObj); //mytsobject will now contain a & b

1

এই উদ্দেশ্যে সবচেয়ে ভাল আমি খুঁজে পেয়েছি হ'ল ক্লাস-ট্রান্সফর্মার। github.com/typestack/class-transformer

আপনি এটি ব্যবহার করেন:

কিছু শ্রেণি:

export class Foo {

    name: string;

    @Type(() => Bar)
    bar: Bar;

    public someFunction = (test: string): boolean => {
        ...
    }
}


import { plainToClass } from 'class-transformer';

export class SomeService {

  anyFunction() {
u = plainToClass(Foo, JSONobj);
 }

আপনি যদি @ টাইপ ডেকোরেটর ব্যবহার করেন তবে নেস্টেড বৈশিষ্ট্যও তৈরি করা হবে।


0

সম্ভবত বাস্তব নয়, তবে সহজ সমাধান:

interface Bar{
x:number;
y?:string; 
}

var baz:Bar = JSON.parse(jsonString);
alert(baz.y);

কঠিন নির্ভরতার জন্যও কাজ !!!


9
এই পদ্ধতির বাস্তবে প্রত্যাশার মতো কাজ হয় না। আপনি যদি রানটাইম ফলাফলগুলি পরিদর্শন করেন তবে তা টাইপ bazহবে এবং টাইপ হবে Objectনা Bar.এটি এই সাধারণ ক্ষেত্রে এটি কাজ করে কারণ Barকোনও পদ্ধতি নেই (কেবলমাত্র প্রাথমিক বৈশিষ্ট্য)। যদি Barএর মতো কোনও পদ্ধতি থাকে তবে isEnabled()এই পদ্ধতিটি ব্যর্থ হবে যেহেতু সেই পদ্ধতিটি সিরিয়ালযুক্ত জেএসওএন স্ট্রিংটিতে নেই।
টড

0

কারখানাগুলি ব্যবহার করে আরেকটি বিকল্প

export class A {

    id: number;

    date: Date;

    bId: number;
    readonly b: B;
}

export class B {

    id: number;
}

export class AFactory {

    constructor(
        private readonly createB: BFactory
    ) { }

    create(data: any): A {

        const createB = this.createB.create;

        return Object.assign(new A(),
            data,
            {
                get b(): B {

                    return createB({ id: data.bId });
                },
                date: new Date(data.date)
            });
    }
}

export class BFactory {

    create(data: any): B {

        return Object.assign(new B(), data);
    }
}

https://github.com/MrAntix/ts-deserialize

এই মত ব্যবহার করুন

import { A, B, AFactory, BFactory } from "./deserialize";

// create a factory, simplified by DI
const aFactory = new AFactory(new BFactory());

// get an anon js object like you'd get from the http call
const data = { bId: 1, date: '2017-1-1' };

// create a real model from the anon js object
const a = aFactory.create(data);

// confirm instances e.g. dates are Dates 
console.log('a.date is instanceof Date', a.date instanceof Date);
console.log('a.b is instanceof B', a.b instanceof B);
  1. আপনার ক্লাস সহজ রাখে
  2. নমনীয়তার জন্য কারখানাগুলিতে ইনজেকশন উপলব্ধ

0

আমি ব্যক্তিগতভাবে @ ইঙ্গো বার্কের # 3 বিকল্পটি পছন্দ করি। এবং আমি জটিল কোডগুলির একটি অ্যারে এবং আদিম উপাত্তের অ্যারে সমর্থন করার জন্য তার কোডগুলি উন্নত করেছি।

interface IDeserializable {
  getTypes(): Object;
}

class Utility {
  static deserializeJson<T>(jsonObj: object, classType: any): T {
    let instanceObj = new classType();
    let types: IDeserializable;
    if (instanceObj && instanceObj.getTypes) {
      types = instanceObj.getTypes();
    }

    for (var prop in jsonObj) {
      if (!(prop in instanceObj)) {
        continue;
      }

      let jsonProp = jsonObj[prop];
      if (this.isObject(jsonProp)) {
        instanceObj[prop] =
          types && types[prop]
            ? this.deserializeJson(jsonProp, types[prop])
            : jsonProp;
      } else if (this.isArray(jsonProp)) {
        instanceObj[prop] = [];
        for (let index = 0; index < jsonProp.length; index++) {
          const elem = jsonProp[index];
          if (this.isObject(elem) && types && types[prop]) {
            instanceObj[prop].push(this.deserializeJson(elem, types[prop]));
          } else {
            instanceObj[prop].push(elem);
          }
        }
      } else {
        instanceObj[prop] = jsonProp;
      }
    }

    return instanceObj;
  }

  //#region ### get types ###
  /**
   * check type of value be string
   * @param {*} value
   */
  static isString(value: any) {
    return typeof value === "string" || value instanceof String;
  }

  /**
   * check type of value be array
   * @param {*} value
   */
  static isNumber(value: any) {
    return typeof value === "number" && isFinite(value);
  }

  /**
   * check type of value be array
   * @param {*} value
   */
  static isArray(value: any) {
    return value && typeof value === "object" && value.constructor === Array;
  }

  /**
   * check type of value be object
   * @param {*} value
   */
  static isObject(value: any) {
    return value && typeof value === "object" && value.constructor === Object;
  }

  /**
   * check type of value be boolean
   * @param {*} value
   */
  static isBoolean(value: any) {
    return typeof value === "boolean";
  }
  //#endregion
}

// #region ### Models ###
class Hotel implements IDeserializable {
  id: number = 0;
  name: string = "";
  address: string = "";
  city: City = new City(); // complex data
  roomTypes: Array<RoomType> = []; // array of complex data
  facilities: Array<string> = []; // array of primitive data

  // getter example
  get nameAndAddress() {
    return `${this.name} ${this.address}`;
  }

  // function example
  checkRoom() {
    return true;
  }

  // this function will be use for getting run-time type information
  getTypes() {
    return {
      city: City,
      roomTypes: RoomType
    };
  }
}

class RoomType implements IDeserializable {
  id: number = 0;
  name: string = "";
  roomPrices: Array<RoomPrice> = [];

  // getter example
  get totalPrice() {
    return this.roomPrices.map(x => x.price).reduce((a, b) => a + b, 0);
  }

  getTypes() {
    return {
      roomPrices: RoomPrice
    };
  }
}

class RoomPrice {
  price: number = 0;
  date: string = "";
}

class City {
  id: number = 0;
  name: string = "";
}
// #endregion

// #region ### test code ###
var jsonObj = {
  id: 1,
  name: "hotel1",
  address: "address1",
  city: {
    id: 1,
    name: "city1"
  },
  roomTypes: [
    {
      id: 1,
      name: "single",
      roomPrices: [
        {
          price: 1000,
          date: "2020-02-20"
        },
        {
          price: 1500,
          date: "2020-02-21"
        }
      ]
    },
    {
      id: 2,
      name: "double",
      roomPrices: [
        {
          price: 2000,
          date: "2020-02-20"
        },
        {
          price: 2500,
          date: "2020-02-21"
        }
      ]
    }
  ],
  facilities: ["facility1", "facility2"]
};

var hotelInstance = Utility.deserializeJson<Hotel>(jsonObj, Hotel);

console.log(hotelInstance.city.name);
console.log(hotelInstance.nameAndAddress); // getter
console.log(hotelInstance.checkRoom()); // function
console.log(hotelInstance.roomTypes[0].totalPrice); // getter
// #endregion

-1

আপনি নীচের মত করতে পারেন

export interface Instance {
  id?:string;
  name?:string;
  type:string;
}

এবং

var instance: Instance = <Instance>({
      id: null,
      name: '',
      type: ''
    });

এটি আসলে আপনার প্রত্যাশিত বস্তুর ধরণের কোনও রানটাইম উদাহরণ তৈরি করবে না। এটি যখন আপনার টাইপটিতে কেবলমাত্র প্রাথমিক বৈশিষ্ট্য রয়েছে তখন এটি কাজ করবে, তবে কোনও ধরণের পদ্ধতি থাকলে ব্যর্থ হবে। ইন্টারফেস সংজ্ঞা এছাড়াও রানটাইম এ উপলব্ধ নয় (শুধুমাত্র বিল্ড সময়)।
টড

-1
**model.ts**
export class Item {
    private key: JSON;
    constructor(jsonItem: any) {
        this.key = jsonItem;
    }
}

**service.ts**
import { Item } from '../model/items';

export class ItemService {
    items: Item;
    constructor() {
        this.items = new Item({
            'logo': 'Logo',
            'home': 'Home',
            'about': 'About',
            'contact': 'Contact',
        });
    }
    getItems(): Item {
        return this.items;
    }
}

নীচের মত সামগ্রীটি কল করুন উদাহরণস্বরূপ:
ইউজার 8390810

<a class="navbar-brand" href="#"> # I keyItems.key.logo}} </a>
user8390810

এটি "[তাত্ক্ষণিক] ক্লাসগুলি প্রয়োজনীয় হিসাবে" বলে মনে হচ্ছে না।
লেক্সিহানকিনস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.