Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON to TypeScript class instance? [duplicate]

I've done quite some research, but I'm not totally satisfied with what I found. Just to be sure here's my question: What is actually the most robust and elegant automated solution for deserializing JSON to TypeScript runtime class instances?

Say I got this class:

class Foo {   name: string;   GetName(): string { return this.name }; } 

And say I got this JSON string for deserialization:

{"name": "John Doe"} 

What's the best and most maintainable solution for getting an instance of a Foo class with the name set to "John Doe" and the method GetName() to work? I'm asking very specifically because I know it's easy to deserialize to a pure data-object. I'm wondering if it's possible to get a class instance with working methods, without having to do any manual parsing or any manual data copying. If a fully automated solution isn't possible, what's the next best solution?

like image 887
Klaus Avatar asked Apr 20 '15 21:04

Klaus


People also ask

How do you avoid reference copy in TypeScript?

So everyone needs to copy an object into another variable but we don't need to reference it, we need to create a new object from the copying object. So, on JavaScript & TypeScript languages, we have the option to do that in multiple ways. But we have used the “newObject = {… Object}” thing commonly in typescript.

How do I copy a class in TypeScript?

One place you can use the object spread syntax to create a new copy of an object from an existing object. To create a new Customer from an existing Customer I can use code like this, providing just one item: Let cust2: Customer; cust2 = {... cust};


1 Answers

This question is quite broad, so I'm going to give a couple of solutions.

Solution 1: Helper Method

Here's an example of using a Helper Method that you could change to fit your needs:

class SerializationHelper {     static toInstance<T>(obj: T, json: string) : T {         var jsonObj = JSON.parse(json);          if (typeof obj["fromJSON"] === "function") {             obj["fromJSON"](jsonObj);         }         else {             for (var propName in jsonObj) {                 obj[propName] = jsonObj[propName]             }         }          return obj;     } } 

Then using it:

var json = '{"name": "John Doe"}',     foo = SerializationHelper.toInstance(new Foo(), json);  foo.GetName() === "John Doe"; 

Advanced Deserialization

This could also allow for some custom deserialization by adding your own fromJSON method to the class (this works well with how JSON.stringify already uses the toJSON method, as will be shown):

interface IFooSerialized {     nameSomethingElse: string; }  class Foo {   name: string;   GetName(): string { return this.name }    toJSON(): IFooSerialized {       return {           nameSomethingElse: this.name       };   }    fromJSON(obj: IFooSerialized) {         this.name = obj.nameSomethingElse;   } } 

Then using it:

var foo1 = new Foo(); foo1.name = "John Doe";  var json = JSON.stringify(foo1);  json === '{"nameSomethingElse":"John Doe"}';  var foo2 = SerializationHelper.toInstance(new Foo(), json);  foo2.GetName() === "John Doe"; 

Solution 2: Base Class

Another way you could do this is by creating your own base class:

class Serializable {     fillFromJSON(json: string) {         var jsonObj = JSON.parse(json);         for (var propName in jsonObj) {             this[propName] = jsonObj[propName]         }     } }  class Foo extends Serializable {     name: string;     GetName(): string { return this.name } } 

Then using it:

var foo = new Foo(); foo.fillFromJSON(json); 

There's too many different ways to implement a custom deserialization using a base class so I'll leave that up to how you want it.

like image 84
David Sherret Avatar answered Sep 24 '22 19:09

David Sherret