JSON到TypeScript类的实例?

我做了相当多的研究,但是我对所发现的东西并不满意。 只是为了确定这是我的问题:什么是实际上最健壮和优雅的自动解决scheme反序列化JSON到TypeScript运行时类实例?

说我有这个class级:

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

并说我得到这个JSONstring的反序列化:

 {"name": "John Doe"} 

获取名为“John Doe”的名称和GetName()方法的Foo类实例的最佳和最可维护的解决scheme是什么? 我非常具体地问,因为我知道很容易反序列化为纯数据对象。 我想知道是否有可能得到一个工作方法的类实例,而不必做任何手动parsing或任何手动数据复制。 如果完全自动化的解决scheme是不可能的,那么下一个最好的解决scheme是什

这个问题相当广泛,所以我要给出几个解决scheme。

解决scheme1:帮助者方法

下面是一个使用Helper方法的例子,你可以改变以适应你的需求:

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

然后使用它:

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

先进的反序列化

这也可以允许一些自定义的反序列化,方法是将自己的fromJSON方法添加到类中(这与JSON.stringify已经如何使用toJSON方法很JSON.stringify ,如下所示:

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

然后使用它:

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

解决scheme2:基类

另一种方法是创build你自己的基类:

 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 } } 

然后使用它:

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

有太多不同的方法来实现使用基类的自定义反序列化,所以我会留下你想要的。

你现在可以使用Object.assign(target, ...sources) 。 按照你的例子,你可以像这样使用它:

 class Foo { name: string; getName(): string { return this.name }; } let fooJson: string = '{"name": "John Doe"}'; let foo: Foo = Object.assign(new Foo(), JSON.parse(fooJson)); console.log(foo.getName()); //returns John Doe 

Object.assign是ECMAScript 2015的一部分,目前在大多数现代浏览器中都可以使用。

实际上,将JSON反序列化为TypeScript运行时类实例的最健壮和优雅的自动化解决scheme是什么?

在ReflectDecorators中使用属性装饰器来logging可以在反序列化过程中使用的运行时可访问的types信息,这提供了一个令人惊讶的干净且广泛适用的方法,同样适合现有的代码。 它也是完全自动化的,也适用于嵌套对象。

这个想法的实现是TypedJSON ,我为这个任务创build了它:

 @JsonObject class Foo { @JsonMember name: string; getName(): string { return this.name }; } 
 var foo = TypedJSON.parse('{"name": "John Doe"}', Foo); foo instanceof Foo; // true foo.getName(); // "John Doe" 

你为什么不能这样做?

 class Foo { constructor(myObj){ Object.assign(this, myObj); } get name() { return this._name; } set name(v) { this._name = v; } } let foo = new Foo({ name: "bat" }); foo.toJSON() //=> your json ... 

我在处理Typescript类和json对象时发现的最佳解决scheme:在您的Typescript类中添加一个构造函数,该类将json数据作为参数。 在该构造函数中,使用jQuery扩展json对象,如下所示:$ .extend(this,jsonData)。 $ .extend允许在添加json对象的属性的同时保持javascript原型。

 export class Foo { Name: string; getName(): string { return this.Name }; constructor( jsonFoo: any ) { $.extend( this, jsonFoo); } } 

在你的ajaxcallback中,将你的jsons翻译成你的脚本对象,如下所示:

 onNewFoo( jsonFoos : any[] ) { let receviedFoos = $.map( jsonFoos, (json) => { return new Foo( json ); } ); // then call a method: let firstFooName = receviedFoos[0].GetName(); } 

如果你不添加构造函数,请在你的ajaxcallback中调用:

 let newFoo = new Foo(); $.extend( newFoo, jsonData); let name = newFoo.GetName() 

…但是如果你想转换子json对象的构造函数也会很有用。 在这里看到我的详细答案。