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?
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.
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};
This question is quite broad, so I'm going to give a couple of solutions.
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";
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With