JSON 到 TypeScript 类实例?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29758765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JSON to TypeScript class instance?
提问by Klaus
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?
我已经做了很多研究,但我对我的发现并不完全满意。只是为了确定这是我的问题:实际上,用于将 JSON 反序列化为 TypeScript 运行时类实例的最强大和最优雅的自动化解决方案是什么?
Say I got this class:
说我上了这门课:
class Foo {
name: string;
GetName(): string { return this.name };
}
And say I got this JSON string for deserialization:
并说我得到了这个用于反序列化的 JSON 字符串:
{"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?
获取名称设置为“John Doe”且方法 GetName() 的 Foo 类实例的最佳和最可维护的解决方案是什么?我问得非常具体,因为我知道反序列化为纯数据对象很容易。我想知道是否有可能获得具有工作方法的类实例,而无需进行任何手动解析或任何手动数据复制。如果完全自动化的解决方案是不可能的,那么下一个最佳解决方案是什么?
回答by David Sherret
This question is quite broad, so I'm going to give a couple of solutions.
这个问题很广泛,所以我将给出几个解决方案。
Solution 1: Helper Method
解决方案 1:辅助方法
Here's an example of using a Helper Method that you could change to fit your needs:
下面是一个使用 Helper Method 的示例,您可以根据需要对其进行更改:
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 fromJSONmethod to the class (this works well with how JSON.stringifyalready uses the toJSONmethod, as will be shown):
这也可以允许通过将您自己的fromJSON方法添加到类中来进行一些自定义反序列化(这对于JSON.stringify已经使用该toJSON方法的方式很有效,如下所示):
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
解决方案 2:基类
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.
使用基类实现自定义反序列化的方法有很多,所以我将把它留给你想要的方式。
回答by Hugo Leao
You can now use Object.assign(target, ...sources). Following your example, you could use it like this:
您现在可以使用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.assignis part of ECMAScript 2015and is currently available in most modern browsers.
Object.assign是ECMAScript 2015 的一部分,目前在大多数现代浏览器中可用。
回答by John Weisz
What is actually the most robust and elegant automated solution for deserializing JSON to TypeScript runtime class instances?
实际上,用于将 JSON 反序列化为 TypeScript 运行时类实例的最健壮和优雅的自动化解决方案是什么?
Using property decoratorswith ReflectDecoratorsto record runtime-accessible type information that can be used during a deserialization process provides a surprisinglyclean and widely adaptable approach, that also fits into existing code beautifully. It is also fully automatable, and works for nested objects as well.
使用带有ReflectDecorators 的属性装饰器来记录可在反序列化过程中使用的运行时可访问的类型信息,提供了一种令人惊讶的干净且具有广泛适应性的方法,它也非常适合现有代码。它也是完全自动化的,也适用于嵌套对象。
An implementation of this idea is TypedJSON, which I created precisely for this task:
这个想法的一个实现是TypedJSON,我正是为此任务创建的:
@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"
回答by amcdnl
Why could you not just do something like this?
为什么你不能做这样的事情?
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 ...
回答by Anthony Brenelière
The best solution I found when dealing with Typescript classes and json objects: add a constructor in your Typescript class that takes the json data as parameter. In that constructor you extend your json object with jQuery, like this: $.extend( this, jsonData). $.extend allows keeping the javascript prototypes while adding the json object's properties.
我在处理 Typescript 类和 json 对象时找到的最佳解决方案:在 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);
}
}
In your ajax callback, translate your jsons in a your typescript object like this:
在您的 ajax 回调中,在您的打字稿对象中翻译您的 json,如下所示:
onNewFoo( jsonFoos : any[] )
{
let receviedFoos = $.map( jsonFoos, (json) => { return new Foo( json ); } );
// then call a method:
let firstFooName = receviedFoos[0].GetName();
}
If you don't add the constructor, juste call in your ajax callback:
如果您不添加构造函数,请在您的 ajax 回调中调用:
let newFoo = new Foo();
$.extend( newFoo, jsonData);
let name = newFoo.GetName()
...but the constructor will be useful if you want to convert the children json object too. See my detailed answer here.
...但是如果您也想转换子 json 对象,构造函数将很有用。在这里查看我的详细答案。

