【问题标题】:Typescript objects serialization?打字稿对象序列化?
【发布时间】:2013-04-28 08:38:34
【问题描述】:

是否有任何方法可以对 Typescript 对象进行 JSON 序列化/反序列化,以便它们不会丢失类型信息?简单的JSON.parse(JSON.stringify) 有太多注意事项。

或者我应该使用临时解决方案?

【问题讨论】:

    标签: javascript json serialization typescript


    【解决方案1】:

    使用接口获取强类型:

    // Creating 
    var foo:any = {};
    foo.x = 3;
    foo.y='123';
    
    var jsonString = JSON.stringify(foo);
    alert(jsonString);
    
    
    // Reading
    interface Bar{
        x:number;
        y?:string; 
    }
    
    var baz:Bar = JSON.parse(jsonString);
    alert(baz.y);
    

    如果需要,请使用类型断言“”。

    【讨论】:

    • 您是为模型创建接口而不是类,还是同时创建类和接口?
    • 这种方法会丢失方法
    • 方法不可序列化。
    【解决方案2】:

    我认为处理这个问题的更好方法是使用 Object.assign(但需要 ECMAScript 2015)。

    给定一个班级

    class Pet {
        name: string;
        age: number;
        constructor(name?: string, age?: number) {
            this.name = name;
            this.age = age;
        }
        getDescription(): string {
            return "My pet " + this.name + " is " + this.age + " years old.";
        }
        static fromJSON(d: Object): Pet {
            return Object.assign(new Pet(), d);
        }
    }
    

    像这样序列化和反序列化...

    var p0 = new Pet("Fido", 5);
    var s = JSON.stringify(p0);
    var p1 = Pet.fromJSON(JSON.parse(s));
    console.log(p1.getDescription());
    

    要将此示例更上一层楼,请考虑嵌套对象...

    class Type {
        kind: string;
        breed: string;
        constructor(kind?: string, breed?: string) {
            this.kind = kind;
            this.breed = breed;
        }
        static fromJSON(d: Object) {
            return Object.assign(new Type(), d);
        }
    }
    class Pet {
        name: string;
        age: number;
        type: Type;
        constructor(name?: string, age?: number) {
            this.name = name;
            this.age = age;
        }
        getDescription(): string {
            return "My pet " + this.name + " is " + this.age + " years old.";
        }
        getFullDescription(): string {
            return "My " + this.type.kind + ", a " + this.type.breed + ", is " + this.age + " years old.";
        }
        static fromJSON(d: Object): Pet {
            var o = Object.assign(new Pet(), d);
            o.type = Type.fromJSON(o['type']);
            return o;
        }
    }
    

    像这样序列化和反序列化...

    var q0 = new Pet("Fido", 5);
    q0.type = new Type("dog", "Pomeranian");
    var t = JSON.stringify(q0);
    var q1 = Pet.fromJSON(JSON.parse(t));
    console.log(q1.getFullDescription());
    

    因此与使用接口不同,这种方法保留了方法。

    【讨论】:

    • 这个问题是你需要允许一个无参数的构造函数,它将对象初始化为不完整的状态。这违反了 RAII 原则,并且可能/将会混淆您图书馆的用户。
    • 我找到了缓解这个问题的方法。看我的回答:stackoverflow.com/a/71623375/4971151
    【解决方案3】:

    目前我发现的最好的方法是使用"jackson-js", jackson-js 是一个允许您使用 ts-decorators 描述类的项目 然后序列化和反序列化保存类型信息。 它支持数组、地图等。

    完整教程:https://itnext.io/jackson-js-powerful-javascript-decorators-to-serialize-deserialize-objects-into-json-and-vice-df952454cf

    简单示例:

    import { JsonProperty, JsonClassType, JsonAlias, ObjectMapper } from 'jackson-js';
    
    class Book {
      @JsonProperty() @JsonClassType({type: () => [String]})
      name: string;
      @JsonProperty() @JsonClassType({type: () => [String]})
      @JsonAlias({values: ['bkcat', 'mybkcat']})
      category: string;
    }
    
    class Writer {
      @JsonProperty() @JsonClassType({type: () => [Number]})
      id: number;
      @JsonProperty() @JsonClassType({type: () => [String]})
      name: string;
      @JsonProperty() @JsonClassType({type: () => [Array, [Book]]})
      books: Book[] = [];
    }
    
    const objectMapper = new ObjectMapper();
    // eslint-disable-next-line max-len
    const jsonData = '{"id":1,"name":"John","books":[{"name":"Learning TypeScript","bkcat":"Web Development"},{"name":"Learning Spring","mybkcat":"Java"}]}';
    const writer = objectMapper.parse<Writer>(jsonData, {mainCreator: () => [Writer]});
    console.log(writer);
    /*
    Writer {
      books: [
        Book { name: 'Learning TypeScript', category: 'Web Development' },
        Book { name: 'Learning Spring', category: 'Java' }
      ],
      id: 1,
      name: 'John'
    }
    */
    

    还有一些其他项目声称做同样的事情 -

    但是当我使用 Ts Map 时,jackson-js 是唯一对我有用的。

    【讨论】:

      【解决方案4】:

      AQuirky answer 适合我。 Object.assign 方法可能会遇到一些问题。我不得不修改我的 tsconfig.json 以包括:

      "compilerOptions": {
          ...
          "lib": ["es2015"],
          ...
      }
      

      【讨论】:

        【解决方案5】:

        首先,您需要创建一个源实体的接口,该接口从 API 接收为 JSON:

        interface UserEntity {
          name: string,
          age: number,
          country_code: string 
        };
        

        第二次使用构造函数实现模型,您可以在其中自定义(camelize)一些字段名称:

          class User  { 
            constructor({ name, age, country_code: countryCode }: UserEntity) {
              Object.assign(this, { name, age, countryCode });
            }
          }
        

        最后使用 JS 对象 jsonUser 创建用户模型的实例”

            const jsonUser = {name: 'Ted', age: 2, country_code: 'US'};
        
            const userInstance = new User(jsonUser);
            
            console.log({ userInstance })
        

        Here is the link to playground

        【讨论】:

          【解决方案6】:

          AQuirky's answer 是一个很好的起点,但正如我在评论中提到的,它的主要问题是它需要允许创建具有未定义字段的对象,然后由他的 fromJSON 方法填充。这违反了RAII 原则,并且可能/将迷惑该类的用户,他们可能会陷入创建不完整 Pet 的陷阱(没有明确指出调用不带参数的构造函数后必须调用 fromJSON() 到填充对象)。

          因此,在他的回答的基础上,这是一种方法,使用 javascript 的prototype chain,在序列化/反序列化后取回类的对象。关键技巧只是在序列化和反序列化之后重新分配正确的原型对象:

          class Foo {}
          foo1 = new Foo();
          foo2 = JSON.parse(JSON.stringify(p1))
          foo2.__proto__ = Foo.prototype;
          

          所以要使用这个技巧修复 AQuirky 的示例,我们可以简单地将他的 fromJSON 函数更改为

          static fromJSON(d: Object): Pet {
              d.__proto__ = Pet.prototype;
              return p
          }
          

          【讨论】:

            猜你喜欢
            • 2015-05-26
            • 2021-07-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-07
            • 1970-01-01
            • 2017-06-12
            • 2017-02-18
            • 1970-01-01
            相关资源
            最近更新 更多