मैं एक टाइपस्क्रिप्ट वर्ग के लिए JSON ऑब्जेक्ट कैसे कर सकता हूं


393

मैंने एक REST सर्वर को दूरस्थ REST सर्वर से पढ़ा। इस JSON ऑब्जेक्ट में एक टाइपस्क्रिप्ट क्लास (डिज़ाइन द्वारा) के सभी गुण हैं। मैंने कैसे टाइप किया जो JSON ऑब्जेक्ट को एक प्रकार var में प्राप्त किया?

मैं एक टाइपस्क्रिप्ट var को पॉप्युलेट नहीं करना चाहता (अर्थात एक कंस्ट्रक्टर है जो इस JSON ऑब्जेक्ट को लेता है)। यह सब-ऑब्जेक्ट द्वारा सब-ऑब्जेक्ट पर बड़ी और कॉपी करना है। सब-ऑब्जेक्ट और प्रॉपर्टी द्वारा संपत्ति में बहुत समय लगेगा।

अपडेट: आप इसे टाइपस्क्रिप्ट इंटरफ़ेस में डाल सकते हैं !


यदि आपका JSON जावा कक्षाओं का उपयोग करके मैप किया गया है तो टाइपस्क्रिप्ट इंटरफेस उत्पन्न करने के लिए आप github.com/vojtechhabarta/typescript-generator का उपयोग कर सकते हैं
Vojta

: मैं एक छोटे से कास्टिंग पुस्तकालय कोड जोड़ने के बाद sulphur-blog.azurewebsites.net/typescript-mini-cast-library
केमिली Wintz

1
JSON ऑब्जेक्ट = जावास्क्रिप्ट ऑब्जेक्ट नोटेशन ऑब्जेक्ट। वहाँ पर्याप्त वस्तुएं नहीं हैं, मैं कहता हूं कि हम अच्छे उपाय के लिए एक जोड़े में फेंक देते हैं।
बग-ए-लॉट

1
मैंने इसके लिए एक टूल बनाया है beshanoe.github.io/json2ts
beshanoe

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

जवाबों:


167

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

यदि आप केवल डेटा के साथ काम कर रहे थे, तो आप बस एक इंटरफ़ेस के लिए एक कास्ट कर सकते हैं (जैसा कि यह पूरी तरह से एक संकलन समय संरचना है), इसके लिए यह आवश्यक होगा कि आप टाइपस्क्रिप्ट क्लास का उपयोग करें जो डेटा इंस्टेंस का उपयोग करता है और उस डेटा के साथ संचालन करता है।

डेटा की नकल करने के कुछ उदाहरण:

  1. AJAX JSON ऑब्जेक्ट को मौजूदा ऑब्जेक्ट में कॉपी करना
  2. पार्स जेन्सन स्ट्रिंग जावास्क्रिप्ट में एक विशेष वस्तु प्रोटोटाइप में

संक्षेप में, आप बस:

var d = new MyRichObject();
d.copyInto(jsonResult);

मैं आपके उत्तर से सहमत हूं। एक अतिरिक्त के रूप में, हालांकि मैं इसे देखने और अभी परीक्षण करने के लिए एक जगह पर नहीं हूं, मुझे लगता है कि उन दो चरणों को एक जाग्रत कार्य के लिए एक परम के रूप में जोड़ा जा सकता है JSON.parse()। दोनों को अभी भी करने की आवश्यकता होगी, लेकिन वाक्यात्मक रूप से उन्हें जोड़ा जा सकता है।
JAAulde

निश्चित रूप से, यह भी काम कर सकता है - मुझे इस बात का अंदाजा नहीं है कि क्या यह कोई और अधिक कुशल होगा हालांकि इसे प्रत्येक संपत्ति के लिए एक अतिरिक्त फ़ंक्शन कॉल करने की आवश्यकता होगी।
वायर्डप्रैरी

निश्चित रूप से इसका जवाब मुझे नहीं मिल रहा था :( जिज्ञासा से बाहर यह क्यों है? यह मुझे लगता है कि जिस तरह से जावास्क्रिप्ट काम करता है कि यह संभव होना चाहिए।
डेविड थिएलेन

नहीं, यह टाइपस्क्रिप्ट में काम नहीं करता है क्योंकि ऐसा करने के लिए जावास्क्रिप्ट में एक सरल तरीका नहीं है।
वायर्डपाइरी

1
के बारे में क्याObject.setPrototypeOf
पेटा

102

मेरे पास एक ही मुद्दा था और मुझे एक पुस्तकालय मिला है जो काम करता है: https://github.com/pleerock/class-transformer

यह इस तरह काम करता है :

let jsonObject = response.json() as Object;
let fooInstance = plainToClass(Models.Foo, jsonObject);
return fooInstance;

यह नेस्टेड चिल्ड का समर्थन करता है लेकिन आपको अपने वर्ग के सदस्य को सजाना होगा।


14
इस शानदार छोटे पुस्तकालय ने इसे पूरी तरह से कम से कम प्रयास के साथ हल किया (अपने @Typeएनोटेशन को न भूलें , हालांकि)। यह उत्तर अधिक श्रेय का हकदार है।
बेनी बोटेमा

अरे वाह !, यह पुस्तकालय इतना छोटा नहीं है कि इसमें आपकी जरूरत की हर चीज हो, यहाँ तक कि आप @ ट्रान्सफॉर्मफॉर्म डेकोरेटर के साथ परिवर्तन को नियंत्रित कर सकते हैं: D
डिएगो फर्नांडो मुरिलो

3
ध्यान दें कि इस पुस्तकालय को अब मुश्किल से बनाए रखा गया है। यह Angular5 + के साथ काम नहीं करता है + और जैसा कि वे अब भी पुल अनुरोधों को विलय नहीं कर रहे हैं, मुझे नहीं लगता कि वे कभी भी जल्द ही इस पर काम करने जा रहे हैं। यह एक महान पुस्तकालय है, हालांकि।
kentor

Angular5 + के लिए एक समाधान है (यह वास्तव में एक कोणीय बग है): github.com/typestack/class-transformer/issues/108
पाक


54

टाइपस्क्रिप्ट में आप एक इंटरफ़ेस और जेनरिक का उपयोग करके एक प्रकार का अभिकथन कर सकते हैं :

var json = Utilities.JSONLoader.loadFromFile("../docs/location_map.json");
var locations: Array<ILocationMap> = JSON.parse(json).location;

जहां ILocationMap आपके डेटा के आकार का वर्णन करता है। इस पद्धति का लाभ यह है कि आपके JSON में अधिक गुण हो सकते हैं लेकिन आकृति इंटरफ़ेस की स्थितियों को संतुष्ट करती है।

मुझे आशा है कि वह मदद करेंगे!


49
FYI करें: यह एक प्रकार का जोर है, न कि कास्ट।
वायर्डपैरी

6
एक प्रकार के दावे और कलाकारों के बीच अंतर के लिए यहां देखें ।
स्टीफन हैंके

7
मुझे उपयोगिताएँ कहाँ मिल सकती हैं। JSONLoader?
हाइपएक्सआर

22
लेकिन इसका कोई तरीका नहीं होगा, जैसा कि उत्तर में बताया गया है।
कोल

1
@StefanHanke URL थोड़ा बदला हुआ सा दिखता है: "टाइप अभिकथन बनाम कास्टिंग"
ruffin

37

यदि आप ES6 का उपयोग कर रहे हैं, तो यह प्रयास करें:

class Client{
  name: string

  displayName(){
    console.log(this.name)
  }
}

service.getClientFromAPI().then(clientData => {

  // Here the client data from API only have the "name" field
  // If we want to use the Client class methods on this data object we need to:
  let clientWithType = Object.assign(new Client(), clientData)

  clientWithType.displayName()
})

लेकिन इस तरह से घोंसला वस्तु पर काम नहीं करेगा , दुख की बात है।


4
उन्होंने टाइपस्क्रिप्ट में इसके लिए कहा।
joe.feser

HI @ joe.feser, मैंने ES6 का उल्लेख किया है क्योंकि इस तरह से 'Object.assign' विधि की आवश्यकता है।
माइगोडर

1
यदि डिफॉल्ट कंस्ट्रक्टर गायब है, Object.create(MyClass.prototype)तो कंस्ट्रक्टर को पूरी तरह से दरकिनार करके टारगेट इंस्टेंस बनाया जा सकता है ।
मार्सेलो

नेस्टेड ऑब्जेक्ट्स लिमिटेशन के बारे में अधिक स्पष्टीकरण stackoverflow.com/questions/22885995/… पर
माइकल फ्रीजिम

28

मुझे JSON की जेनेरिक कास्टिंग पर एक बहुत ही दिलचस्प लेख मिला एक टाइपस्क्रिप्ट क्लास के लिए:

http://cloudmark.github.io/Json-Mapping/

आप निम्नलिखित कोड के साथ समाप्त होते हैं:

let example = {
                "name": "Mark", 
                "surname": "Galea", 
                "age": 30, 
                "address": {
                  "first-line": "Some where", 
                  "second-line": "Over Here",
                  "city": "In This City"
                }
              };

MapUtils.deserialize(Person, example);  // custom class

20

TLDR: एक लाइनर

// This assumes your constructor method will assign properties from the arg.
.map((instanceData: MyClass) => new MyClass(instanceData));

विस्तृत जवाब

मैं Object.assign दृष्टिकोण की सिफारिश नहीं करूंगा, क्योंकि यह अनुचित रूप से आपके वर्ग के उदाहरण को अप्रासंगिक गुणों (साथ ही परिभाषित क्लोजर) के साथ लिट कर सकता है जो कि कक्षा के भीतर ही घोषित नहीं किए गए थे।

जिस वर्ग में आप डिस्क्राइबलाइज करने की कोशिश कर रहे हैं, मैं यह सुनिश्चित करना चाहता हूं कि आप जिस भी प्रॉपर्टीज को डिफाइरलाइज्ड करना चाहते हैं उसे परिभाषित करें (शून्य, खाली एरे, आदि)। प्रारंभिक मानों के साथ अपनी संपत्तियों को परिभाषित करके, आप वर्ग दृश्य के सदस्यों को मूल्यों को निर्दिष्ट करने के लिए पुनरावृत्त करने की कोशिश करते समय उनकी दृश्यता को उजागर करते हैं (देखें deserialize विधि)।

export class Person {
  public name: string = null;
  public favoriteSites: string[] = [];

  private age: number = null;
  private id: number = null;
  private active: boolean;

  constructor(instanceData?: Person) {
    if (instanceData) {
      this.deserialize(instanceData);
    }
  }

  private deserialize(instanceData: Person) {
    // Note this.active will not be listed in keys since it's declared, but not defined
    const keys = Object.keys(this);

    for (const key of keys) {
      if (instanceData.hasOwnProperty(key)) {
        this[key] = instanceData[key];
      }
    }
  }
}

ऊपर दिए गए उदाहरण में, मैंने बस एक deserialize विधि बनाई। एक वास्तविक दुनिया उदाहरण में, मैं इसे पुन: प्रयोज्य आधार वर्ग या सेवा पद्धति में केंद्रीकृत करूंगा।

यह कैसे एक http सम्मान की तरह कुछ में इस का उपयोग करने के लिए है ...

this.http.get(ENDPOINT_URL)
  .map(res => res.json())
  .map((resp: Person) => new Person(resp) ) );

यदि tslint / ide में तर्क प्रकार के असंगत होने की शिकायत होती है, तो तर्क को कोणीय कोष्ठक का उपयोग करके उसी प्रकार में डालें <YourClassName>, उदाहरण:

const person = new Person(<Person> { name: 'John', age: 35, id: 1 });

यदि आपके पास कक्षा के सदस्य हैं जो एक विशिष्ट प्रकार के हैं (उर्फ: दूसरे वर्ग का उदाहरण), तो आप उन्हें गेट्टर / सेटर विधियों के माध्यम से टाइप किए गए उदाहरणों में डाल सकते हैं।

export class Person {
  private _acct: UserAcct = null;
  private _tasks: Task[] = [];

  // ctor & deserialize methods...

  public get acct(): UserAcct {
    return this.acct;
  }
  public set acct(acctData: UserAcct) {
    this._acct = new UserAcct(acctData);
  }

  public get tasks(): Task[] {
    return this._tasks;
  }

  public set tasks(taskData: Task[]) {
    this._tasks = taskData.map(task => new Task(task));
  }
}

उपरोक्त उदाहरण दोनों एसीट और कार्यों की सूची को उनके संबंधित वर्ग उदाहरणों में शामिल करेगा।


मुझे यह त्रुटि संदेश मिला है: '{name: string, age: number, id: number}' टाइप करके 'व्यक्ति' टाइप नहीं किया जा सकता। संपत्ति 'आईडी' टाइप 'व्यक्ति' में निजी है, लेकिन टाइप में नहीं '{नाम: स्ट्रिंग, आयु: संख्या, आईडी: संख्या}'
utiq

मुझे इसका उपयोग कैसे करना चाहिए? क्या मुझे विशिष्ट प्रकार के दृष्टिकोण का उपयोग करना होगा और इसके लिए गेट्टर और सेटर जोड़ना होगा?
तदिजा बागरिक

@TimothyParez आप कार्य कब सेट करते हैं?
कया

मैंने भी कुछ ऐसा ही करने की कोशिश की थी, लेकिन कंसोल कंसोल पर काम करने के दौरान मेरा काम खाली है।
काय

इसे संकलित करने के लिए मुझे कक्षा में एक इंडेक्स सिग्नेचर जोड़ना था: एक्सपोर्ट क्लास पर्सन {[की: स्ट्रिंग]:
असिमोव

18

मान लें कि आपके टाइपस्क्रिप्ट वर्ग के रूप में json के समान गुण हैं, तो आपको अपने JSON गुणों को अपनी टाइपस्क्रिप्ट ऑब्जेक्ट पर कॉपी करने की आवश्यकता नहीं है। आपको बस अपने टाइपस्क्रिप्ट ऑब्जेक्ट को कंस्ट्रक्टर में json डेटा पास करना होगा।

आपके अजाक्स कॉलबैक में, आपको एक कंपनी मिलती है:

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

   // call the methods on your newCompany object ...
}

उस काम को करने के लिए:

1) अपने टाइपस्क्रिप्ट क्लास में एक कंस्ट्रक्टर जोड़ें जो कि json डेटा को पैरामीटर के रूप में लेता है। उस कंस्ट्रक्टर में आप अपने json ऑब्जेक्ट को jQuery के साथ बढ़ाते हैं, जैसे $.extend( this, jsonData):। $ .extend जावास्क्रिप्ट ऑब्जेक्ट के गुणों को जोड़ते हुए जावास्क्रिप्ट प्रोटोटाइप रखने की अनुमति देता है।

2) ध्यान दें कि आपको लिंक्ड ऑब्जेक्ट के लिए ऐसा ही करना होगा। उदाहरण में कर्मचारियों के मामले में, आप एक कंस्ट्रक्टर भी बनाते हैं जो कर्मचारियों के लिए json डेटा का हिस्सा लेता है। आप कर्मचारी वस्तुओं को टाइप करने के लिए json कर्मचारियों का अनुवाद करने के लिए $ .map कहते हैं।

export class Company
{
    Employees : Employee[];

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

        if ( jsonData.Employees )
            this.Employees = $.map( jsonData.Employees , (emp) => {
                return new Employee ( emp );  });
    }
}

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

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

यह सबसे अच्छा समाधान है जो मैंने टाइपस्क्रिप्ट क्लास और जोंस ऑब्जेक्ट्स के साथ काम करते समय पाया।


मैं इंटरफेस को लागू करने और बनाए रखने पर इस समाधान को पसंद करता हूं, क्योंकि मेरे एंगुलर 2 अनुप्रयोगों में एक वास्तविक एप्लिकेशन मॉडल है जो कि मेरे एप्लिकेशन उपभोग करने वाले वेबसर्विस के मॉडल के लिए अलग हो सकता है। इसमें निजी डेटा और परिकलित गुण हो सकते हैं।
एंथनी ब्रेनेलीयर

7
कोणीय परियोजनाओं में JQuery का उपयोग करना एक भयानक विचार है। और अगर आपके मॉडलों में उन पर कार्यों का एक गुच्छा होता है, तो वे अब मॉडल नहीं हैं।
Davor करें

1
@ आप POJO, या मॉडल का मतलब है? POJO (मूल रूप से सादे वस्तुएं) का कोई कार्य नहीं है, जबकि मॉडल एक व्यापक शब्द है, और इसमें रिपॉजिटरी भी शामिल है। पीओजेओ के विपरीत, रिपोजिटरी पैटर्न, कार्यों के बारे में है, लेकिन यह अभी भी मॉडल है।
forsberg

@Davor: जब तक आप DOM का हेरफेर करने के लिए इसका उपयोग नहीं करते हैं, तब तक Angular प्रोजेक्ट्स में JQuery का उपयोग करना एक बुरा विचार नहीं है, जो वास्तव में एक भयानक विचार है। मैं अपनी कोणीय परियोजनाओं के लिए आवश्यक किसी भी पुस्तकालय का उपयोग करता हूं, और jQuery के लिए यह एक विकल्प नहीं है क्योंकि मेरी परियोजना सिग्नलआर का उपयोग करती है जो इस पर निर्भर करती है। कक्षाओं के मामले में, अब जावास्क्रिप्ट ES6 द्वारा उपयोग किया जाता है, डेटा को उन गुणों के साथ एक्सेस किया जाता है जो फ़ंक्शन होते हैं जो डेटा को मेमोरी में संग्रहीत करने के तरीके को एन्क्रिप्ट करते हैं। कंस्ट्रक्टरों के लिए, एक उचित तरीका है जो कारखानों का उपयोग कर रहा है।
एंथनी ब्रेनेलीयर

REST के लिए सादे डेटा मॉडल के बारे में ओपी स्पष्ट रूप से है। आप इसे अनावश्यक रूप से जटिल बना रहे हैं, दोस्तों। और हाँ, आप अतिरिक्त सामान के लिए Jquery का उपयोग कर सकते हैं, लेकिन आप 1% का उपयोग करने के लिए एक बड़े पुस्तकालय का आयात कर रहे हैं। अगर मैंने कभी देखा है तो यह एक कोड गंध है।
डावोर

18

स्वचालित रूप से जांच करने के लिए अभी तक कुछ भी नहीं है कि क्या JSON ऑब्जेक्ट आपको सर्वर से प्राप्त हुआ है (अपेक्षित है) टाइपस्क्रिप्ट के इंटरफ़ेस गुणों के अनुरूप है। लेकिन आप User-Defined Type Guards का उपयोग कर सकते हैं

निम्नलिखित इंटरफ़ेस और एक मूर्खतापूर्ण json वस्तु को ध्यान में रखते हुए (यह किसी भी प्रकार हो सकता है):

interface MyInterface {
    key: string;
 }

const json: object = { "key": "value" }

तीन संभावित तरीके:

A. वैरिएबल के बाद रखा जाने वाला अभिकथन या साधारण स्टेटिक कास्ट

const myObject: MyInterface = json as MyInterface;

B. सरल स्थिर कलाकारों, चर से पहले और हीरे के बीच

const myObject: MyInterface = <MyInterface>json;

C. उन्नत गतिशील कास्ट, आप अपने आप को ऑब्जेक्ट की संरचना की जांच करते हैं

function isMyInterface(json: any): json is MyInterface {
    // silly condition to consider json as conform for MyInterface
    return typeof json.key === "string";
}

if (isMyInterface(json)) {
    console.log(json.key)
}
else {
        throw new Error(`Expected MyInterface, got '${json}'.`);
}

आप ऐसा कर सकते हैं इस उदाहरण के साथ यहां खेल हैं

ध्यान दें कि isMyInterfaceफ़ंक्शन लिखने के लिए यहां कठिनाई है । मुझे आशा है कि टीएस जल्दी या बाद में रनिंग के लिए जटिल टाइपिंग को निर्यात करने के लिए जोड़ देगा और जरूरत पड़ने पर रनटाइम को ऑब्जेक्ट की संरचना की जांच करने देगा। अभी के लिए, आप या तो एक json स्कीमा सत्यापनकर्ता का उपयोग कर सकते हैं जिसका उद्देश्य लगभग एक ही है या यह रनटाइम प्रकार चेक फ़ंक्शन जनरेटर है


1
आपका उत्तर शीर्ष पर होना चाहिए मुझे लगता है कि
afzalex

निश्चित रूप से। यह सबसे अच्छा उत्तर है जो सीधे ts वेबसाइट पर निर्भर करता है।
बुरक काराकुस

15

मेरे मामले में यह काम करता है। मैंने कार्य Object.assign (लक्ष्य, स्रोत ...) का उपयोग किया । सबसे पहले, सही ऑब्जेक्ट का निर्माण, फिर डेटा को json ऑब्जेक्ट से लक्ष्य तक कॉपी करता है।

let u:User = new User();
Object.assign(u , jsonUsers);

और उपयोग का एक और अधिक उन्नत उदाहरण। सरणी का उपयोग करके एक उदाहरण।

this.someService.getUsers().then((users: User[]) => {
  this.users = [];
  for (let i in users) {
    let u:User = new User();
    Object.assign(u , users[i]);
    this.users[i] = u;
    console.log("user:" + this.users[i].id);
    console.log("user id from function(test it work) :" + this.users[i].getId());
  }

});

export class User {
  id:number;
  name:string;
  fullname:string;
  email:string;

  public getId(){
    return this.id;
  }
}

जब आपके पास निजी संपत्ति होती है तो क्या होता है?
पूर्वांश

क्योंकि jsonUser ऑब्जेक्ट कोई उपयोगकर्ता वर्ग नहीं है। ऑपरेशन के बिना Object.assign (u, jsonUsers); आप getId () फ़ंक्शन का उपयोग नहीं कर सकते। असाइन होने के बाद ही आपको एक वैध उपयोगकर्ता ऑब्जेक्ट मिलता है जिसमें आप getId () फ़ंक्शन का उपयोग कर सकते हैं। GetId () फ़ंक्शन केवल उदाहरण के लिए है कि ऑपरेशन सफल था।
Adam111p

आप अस्थायी this.users[i] = new User(); Object.assign(this.users[i], users[i])
संस्करण

या इससे भी बेहतर रिटर्न रिटर्न का उपयोग करें:this.users[i] = Object.assign(new User(), users[i]);
साइबर स्टेप

यह लंबा संस्करण केवल स्पष्टीकरण के लिए है। आप कोड को जितना चाहें उतना छोटा कर सकते हैं :)
Adam111p

6

जबकि यह प्रति से कास्टिंग नहीं है; मैंने एक उपयोगी विकल्प होने के लिए https://github.com/JohnWhiteTB/TypedJSON पाया है ।

@JsonObject
class Person {
    @JsonMember
    firstName: string;

    @JsonMember
    lastName: string;

    public getFullname() {
        return this.firstName + " " + this.lastName;
    }
}
var person = TypedJSON.parse('{ "firstName": "John", "lastName": "Doe" }', Person);

person instanceof Person; // true
person.getFullname(); // "John Doe"

1
यह कास्टिंग नहीं है, यह वास्तव में क्या करता है?
डेनियल

1
इस समाधान के लिए बहुत सारी टिप्पणियों की आवश्यकता होती है। क्या वास्तव में कोई आसान तरीका नहीं है?
JPNotADragon

3

आप interfaceअपने प्रकार का एक बना सकते हैं ( SomeType) और उसमें ऑब्जेक्ट को डाल सकते हैं।

const typedObject: SomeType = <SomeType> responseObject;

3

यदि आपको एक टाइपस्क्रिप्ट क्लास में अपना जसन ऑब्जेक्ट डालना है और इसके इंस्टेंस मेथड्स उपलब्ध हैं, जिसके परिणामस्वरूप आपको उपयोग करने की आवश्यकता है Object.setPrototypeOf, जैसे मैंने कोड स्निपेट बोले में किया था:

Object.setPrototypeOf(jsonObject, YourTypescriptClass.prototype)

2

ज्यादातर सही, लेकिन बहुत कुशल जवाब नहीं के साथ एक पुराना सवाल। यह मेरा प्रस्ताव है:

एक बेस क्लास बनाएं जिसमें इनिट () मेथड और स्टैटिक कास्ट मेथड्स (सिंगल ऑब्जेक्ट और एरे के लिए) हों। स्थैतिक विधियाँ कहीं भी हो सकती हैं; बेस क्लास और इनिट के साथ संस्करण () बाद में आसान एक्सटेंशन की अनुमति देता है।

export class ContentItem {
    // parameters: doc - plain JS object, proto - class we want to cast to (subclass of ContentItem)
    static castAs<T extends ContentItem>(doc: T, proto: typeof ContentItem): T {
        // if we already have the correct class skip the cast
        if (doc instanceof proto) { return doc; }
        // create a new object (create), and copy over all properties (assign)
        const d: T = Object.create(proto.prototype);
        Object.assign(d, doc);
        // reason to extend the base class - we want to be able to call init() after cast
        d.init(); 
        return d;
    }
    // another method casts an array
    static castAllAs<T extends ContentItem>(docs: T[], proto: typeof ContentItem): T[] {
        return docs.map(d => ContentItem.castAs(d, proto));
    }
    init() { }
}

इसी तरह के मैकेनिक्स ( असाइन () के साथ ) का उल्लेख @ Adam111p पोस्ट में किया गया है। इसे करने के लिए बस एक और (अधिक पूर्ण) तरीका है। @ टिमोथी पेरेस असाइनमेंट () के लिए महत्वपूर्ण है , लेकिन यह पूरी तरह से यहाँ उपयुक्त है।

एक व्युत्पन्न (वास्तविक) वर्ग को लागू करें:

import { ContentItem } from './content-item';

export class SubjectArea extends ContentItem {
    id: number;
    title: string;
    areas: SubjectArea[]; // contains embedded objects
    depth: number;

    // method will be unavailable unless we use cast
    lead(): string {
        return '. '.repeat(this.depth);
    }

    // in case we have embedded objects, call cast on them here
    init() {
        if (this.areas) {
            this.areas = ContentItem.castAllAs(this.areas, SubjectArea);
        }
    }
}

अब हम सेवा से प्राप्त एक वस्तु को डाल सकते हैं:

const area = ContentItem.castAs<SubjectArea>(docFromREST, SubjectArea);

सबजेक्टआरे ऑब्जेक्ट्स के सभी पदानुक्रम में सही वर्ग होगा।

एक उपयोग मामला / उदाहरण; एक कोणीय सेवा (फिर से आधार वर्ग) बनाएं:

export abstract class BaseService<T extends ContentItem> {
  BASE_URL = 'http://host:port/';
  protected abstract http: Http;
  abstract path: string;
  abstract subClass: typeof ContentItem;

  cast(source: T): T {
    return ContentItem.castAs(source, this.subClass);
  }
  castAll(source: T[]): T[] {
    return ContentItem.castAllAs(source, this.subClass);
  }

  constructor() { }

  get(): Promise<T[]> {
    const value = this.http.get(`${this.BASE_URL}${this.path}`)
      .toPromise()
      .then(response => {
        const items: T[] = this.castAll(response.json());
        return items;
      });
    return value;
  }
}

उपयोग बहुत सरल हो जाता है; एक क्षेत्र सेवा बनाएँ:

@Injectable()
export class SubjectAreaService extends BaseService<SubjectArea> {
  path = 'area';
  subClass = SubjectArea;

  constructor(protected http: Http) { super(); }
}

सेवा का तरीका () विधि एक सरणी का वादा लौटाएगी जो पहले से ही डाली गई विषय वस्तु के रूप में (संपूर्ण पदानुक्रम)

अब कहते हैं, हमारे पास एक और वर्ग है:

export class OtherItem extends ContentItem {...}

एक ऐसी सेवा बनाना जो डेटा को पुन: प्राप्त करता है और सही वर्ग के लिए डाली जाती है, यह उतना ही सरल है:

@Injectable()
export class OtherItemService extends BaseService<OtherItem> {
  path = 'other';
  subClass = OtherItem;

  constructor(protected http: Http) { super(); }
}

2

इंटरफ़ेस से विस्तारित वर्ग का उपयोग करें।

फिर:

Object.assign(
                new ToWhat(),
                what
              )

और सबसे अच्छा:

Object.assign(
                    new ToWhat(),
                    <IDataInterface>what
                  )

ToWhat DataInterface का कंट्रोलर बन जाता है।


1

https://jvilk.com/MakeTypes/

आप इस साइट का उपयोग आपके लिए एक प्रॉक्सी बनाने के लिए कर सकते हैं। यह एक वर्ग उत्पन्न करता है और आपके इनपुट JSON ऑब्जेक्ट को पार्स और मान्य कर सकता है।


0

Lates TS में आप इस तरह कर सकते हैं:

const isMyInterface = (val: any): val is MyInterface => {
  if (!val) { return false; }
  if (!val.myProp) { return false; }
  return true;
};

और इस तरह से उपयोगकर्ता की तुलना में:

if (isMyInterface(data)) {
 // now data will be type of MyInterface
}

0

मैं इसी तरह की जरूरत में भाग गया। मैं कुछ ऐसा चाहता था जो मुझे / JSON से एक आसान परिवर्तन देगा जो REST एपि कॉल से / विशिष्ट वर्ग परिभाषा से आ रहा है। जो समाधान मुझे मिले हैं वे अपर्याप्त थे या मेरी कक्षाओं के कोड को फिर से लिखना और एनोटेशन या सिमिलर जोड़ना था।

मैं चाहता था कि कुछ ऐसा हो जैसे कि जीएसओएन का उपयोग जावा में जेन्स वस्तुओं से / से कक्षाओं को क्रमबद्ध / deserialize करने के लिए किया जाता है।

बाद की जरूरत के साथ संयुक्त, कि कनवर्टर जेएस में भी काम करेगा, मैंने अपना पैकेज लिखना समाप्त कर दिया।

यह हालांकि, ओवरहेड का एक छोटा सा है। लेकिन जब यह शुरू हुआ तो इसे जोड़ने और संपादन में बहुत सुविधाजनक है।

आप मॉड्यूल को इसके साथ आरंभ करते हैं:

  1. रूपांतरण स्कीमा - खेतों के बीच मानचित्र बनाने और यह निर्धारित करने की अनुमति देता है कि रूपांतरण कैसे किया जाएगा
  2. कक्षाओं का नक्शा सरणी
  3. रूपांतरण फ़ंक्शन मानचित्र - विशेष रूपांतरणों के लिए।

फिर आपके कोड में, आप इनिशियलाइज्ड मॉड्यूल का उपयोग करते हैं जैसे:

const convertedNewClassesArray : MyClass[] = this.converter.convert<MyClass>(jsonObjArray, 'MyClass');

const convertedNewClass : MyClass = this.converter.convertOneObject<MyClass>(jsonObj, 'MyClass');

या, JSON को:

const jsonObject = this.converter.convertToJson(myClassInstance);

Npm पैकेज के लिए इस लिंक का उपयोग करें और मॉड्यूल के साथ काम करने के तरीके के बारे में भी विस्तृत विवरण: json-class-converter

इसके अलावा इसे
कोणीय उपयोग के लिए लपेटा : कोणीय-ज्सन-क्लास-कनवर्टर


0

ऑब्जेक्ट को पास करें जैसा कि क्लास कंस्ट्रक्टर को है; कोई सम्मेलन या जाँच नहीं

interface iPerson {
   name: string;
   age: number;
}

class Person {
   constructor(private person: iPerson) { }

   toString(): string {
      return this.person.name + ' is ' + this.person.age;
   }  
}


// runs this as // 
const object1 = { name: 'Watson1', age: 64 };
const object2 = { name: 'Watson2' };            // age is missing

const person1 = new Person(object1);
const person2 = new Person(object2 as iPerson); // now matches constructor

console.log(person1.toString())  // Watson1 is 64
console.log(person2.toString())  // Watson2 is undefined

0

आप इस npm पैकेज का उपयोग कर सकते हैं। https://www.npmjs.com/package/class-converter

उदाहरण के लिए, इसका उपयोग करना आसान है:

class UserModel {
  @property('i')
  id: number;

  @property('n')
  name: string;
}

const userRaw = {
  i: 1234,
  n: 'name',
};

// use toClass to convert plain object to class
const userModel = toClass(userRaw, UserModel);
// you will get a class, just like below one
// const userModel = {
//   id: 1234,
//   name: 'name',
// }

0

व्यक्तिगत रूप से मुझे यह भयावह लगता है कि टाइपस्क्रिप्ट ऑब्जेक्ट के प्रकार को निर्दिष्ट करने के लिए एक समापन बिंदु परिभाषा की अनुमति नहीं देता है। जैसा कि यह प्रतीत होता है कि यह वास्तव में मामला है, मैं वही करूंगा जो मैंने अन्य भाषाओं के साथ किया है, और वह यह है कि मैं JSON ऑब्जेक्ट को वर्ग परिभाषा से अलग कर दूंगा, और कक्षा की परिभाषा को JSON ऑब्जेक्ट को इसके एकमात्र डेटा सदस्य के रूप में उपयोग करना होगा। ।

मैं बॉयलरप्लेट कोड को तिरस्कृत करता हूं, इसलिए मेरे लिए यह आमतौर पर टाइप करते समय कम से कम कोड के साथ वांछित परिणाम प्राप्त करने का मामला है।

निम्नलिखित JSON ऑब्जेक्ट संरचना परिभाषाओं पर विचार करें - ये वही होंगे जो आपको एक समापन बिंदु पर प्राप्त होंगे, वे केवल संरचना परिभाषाएं हैं, कोई विधियाँ नहीं।

interface IAddress {
    street: string;
    city: string;
    state: string;
    zip: string;
}

interface IPerson {
    name: string;
    address: IAddress;
}

यदि हम ऑब्जेक्ट ओरिएंटेड शब्दों में उपरोक्त के बारे में सोचते हैं, तो उपरोक्त इंटरफेस क्लास नहीं हैं क्योंकि वे केवल एक डेटा संरचना को परिभाषित करते हैं। OO शब्दों में एक वर्ग डेटा और उस पर चलने वाले कोड को परिभाषित करता है।

इसलिए अब हम एक वर्ग को परिभाषित करते हैं जो डेटा और उस पर काम करने वाले कोड को निर्दिष्ट करता है ...

class Person {
    person: IPerson;

    constructor(person: IPerson) {
        this.person = person;
    }

    // accessors
    getName(): string {
        return person.name;
    }

    getAddress(): IAddress {
        return person.address;
    }

    // You could write a generic getter for any value in person, 
    // no matter how deep, by accepting a variable number of string params

    // methods
    distanceFrom(address: IAddress): float {
        // Calculate distance from the passed address to this persons IAddress
        return 0.0;
    }
}

और अब हम बस किसी भी वस्तु में आकर इपर्सन संरचना के अनुरूप हो सकते हैं और हमारे रास्ते में हो सकते हैं ...

   Person person = new Person({
            name: "persons name",
            address: {
                street: "A street address",
                city: "a city",
                state: "a state",
                zip: "A zipcode"
            }
        });

उसी अंदाज में अब हम आपके साथ अपने समापन बिंदु पर प्राप्त वस्तु को किसी चीज़ की तर्ज पर संसाधित कर सकते हैं ...

Person person = new Person(req.body);    // As in an object received via a POST call

person.distanceFrom({ street: "Some street address", etc.});

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


0

घोषणा के रूप में 'का प्रयोग करें:

const data = JSON.parse(response.data) as MyClass;

इस तकनीक का दो साल पहले से इस जवाब में उल्लेख किया गया था , और जैसा कि कहीं और चर्चा की गई है, इसमें कोई भी फ़ंक्शन नहीं जोड़ा गया है जिसे घोषित किया जा सकता है MyClass
हेरिटिक बंदर

-1

यह एक सरल और वास्तव में अच्छा विकल्प है

let person = "{"name":"Sam","Age":"30"}";

const jsonParse: ((key: string, value: any) => any) | undefined = undefined;
let objectConverted = JSON.parse(textValue, jsonParse);

और फिर आपके पास होगा

objectConverted.name

-1

मैंने यहां इस लाइब्रेरी का उपयोग किया: https://github.com/pleerock/class-transformer

<script lang="ts">
    import { plainToClass } from 'class-transformer';
</script>

कार्यान्वयन:

private async getClassTypeValue() {
  const value = await plainToClass(ProductNewsItem, JSON.parse(response.data));
}

कभी-कभी आपको यह समझने के लिए कि यह एक JSON स्वरूपित डेटा है, सादातोक्लास के JSON मानों को पार्स करना होगा


'क्लास-ट्रांसफॉर्मर' लाइब्रेरी को पहले से ही stackoverflow.com/a/40042282/52277 से
माइकल फ्रीजिम

-1

मैं बैकएंड पर फ्रंटेंड और स्प्रिंग बूट एप्लिकेशन पर कोणीय 6 का उपयोग कर रहा हूं जो जावा ऑब्जेक्ट्स को लौटाता है। मुझे केवल कोणीय अनुप्रयोग पर एक समान वर्ग को परिभाषित करने की आवश्यकता है जिसमें मिलान गुण हैं और फिर मैं ऑब्जेक्ट को 'कोणीय वर्ग ऑब्जेक्ट ( कंपनी के रूप में COMP) के रूप में स्वीकार कर सकता हूं में नीचे उदाहरण में) के ।

उदाहरण के लिए नीचे अंतिम कोड देखें। अगर कुछ और स्पष्टता चाहिए तो मुझे टिप्पणियों में बताएं।

  createCompany() {
    let company = new Company();
    company.name = this.companyName;

    this.companyService.createCompany(company).subscribe(comp => {
       if (comp !== null) {
        this.employerAdminCompany = comp as Company;
      }
    });
  }

जहाँ कंपनी स्प्रिंग बूट ऐप में एक इकाई वस्तु है और एंगुलर में एक वर्ग भी है।

export class Company {
    public id: number;
    public name: string;
    public owner: User;
    public locations: Array<Location>;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.