JSON到TypeScript类的实例?

Kla*_*aus 90 json deserialization typescript

我做了很多研究,但我对我发现的东西并不完全满意.只是为了确定这是我的问题:什么是将JSON反序列化为TypeScript运行时类实例的最强大,最优雅的自动化解决方案?

说我上了这堂课:

class Foo {
  name: string;
  GetName(): string { return this.name };
}
Run Code Online (Sandbox Code Playgroud)

并说我有这个JSON字符串用于反序列化:

{"name": "John Doe"}
Run Code Online (Sandbox Code Playgroud)

获取名称设置为"John Doe"和GetName()方法的Foo类实例的最佳和最易维护的解决方案是什么?我非常具体地问,因为我知道很容易反序列化为纯数据对象.我想知道是否可以使用工作方法获取类实例,而无需进行任何手动解析或任何手动数据复制.如果无法实现全自动化解决方案,那么下一个最佳解决方案是什么?

Dav*_*ret 70

这个问题相当广泛,所以我将提出几个解决方案.

解决方案1:辅助方法

以下是使用帮助程序方法的示例,您可以根据自己的需要进行更改:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

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

foo.GetName() === "John Doe";
Run Code Online (Sandbox Code Playgroud)

高级反序列化

这也可以通过向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;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

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";
Run Code Online (Sandbox Code Playgroud)

解决方案2:基类

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

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 }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

var foo = new Foo();
foo.fillFromJSON(json);
Run Code Online (Sandbox Code Playgroud)

使用基类实现自定义反序列化的方法太多了,所以我会把它留给你想要的方式.

  • @Klaus是一个问题,如果您有嵌套对象.例如,如果`Foo`有一个类型为`Bar`的属性.这个问题有点复杂...... (5认同)

Hug*_*eao 45

你现在可以使用了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
Run Code Online (Sandbox Code Playgroud)

Object.assignECMAScript 2015的一部分,目前在大多数现代浏览器中都可用.

  • 不适用于嵌套对象 (12认同)
  • 万一`Foo`缺少默认的构造函数,可以通过`Object.create(Foo.prototype)`创建目标实例,而完全绕开该构造函数。 (2认同)
  • 使用正常的“JSON”解析时,嵌套对象不会映射到其强类型。我建议使用像 [class-transformer](https://www.npmjs.com/package/class-transformer) 这样的包来正确映射任何嵌套对象的对象及其类型。他们的文档相对容易理解并且易于使用 (2认同)

Joh*_*isz 16

什么是将JSON反序列化为TypeScript运行时类实例的最强大,最优雅的自动化解决方案?

使用带有ReflectDecorators的属性修饰符来记录可在反序列化过程中使用的运行时可访问类型信息,这提供了一种令人惊讶的干净且适应性广泛的方法,它也非常适合现有代码.它也是完全可自动化的,也适用于嵌套对象.

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

@JsonObject
class Foo {
    @JsonMember
    name: string;

    getName(): string { return this.name };
}
Run Code Online (Sandbox Code Playgroud)
var foo = TypedJSON.parse('{"name": "John Doe"}', Foo);

foo instanceof Foo; // true
foo.getName(); // "John Doe"
Run Code Online (Sandbox Code Playgroud)

  • 如果你想让更多的人使用你的库,我建议你在npm上发布并修复那些打字....用一个指向你的index.d.ts文件的package.json (15认同)