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对象的构造函数也会很有用。 在这里看到我的详细答案。