首页 文章

JSON到TypeScript类的实例? [重复]

提问于
浏览
74

这个问题在这里已有答案:

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

说我上了这堂课:

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

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

{"name": "John Doe"}

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

5 回答

  • 0

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

    解决方案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;
        }
    }
    

    然后使用它:

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

    Advanced Deserialization

    这也可以通过向类中添加自己的 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;
      }
    }
    

    然后使用它:

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

    解决方案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 }
    }
    

    然后使用它:

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

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

  • 4

    您现在可以使用 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.assignECMAScript 2015的一部分,目前在大多数现代浏览器中都可用 .

  • 58

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

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

    这个想法的实现是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"
    
  • 13

    为什么你不能做这样的事情?

    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 ...
    
  • 39

    我在处理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);
        }
    }
    

    在你的ajax回调中,在你的打字稿对象中翻译你的jsons,如下所示:

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

    如果你没有添加构造函数,请在你的ajax回调中调用juste:

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

    ...但是如果你想转换子json对象,构造函数也会很有用 . 请参阅我的详细答案here .

相关问题