typescript 类型脚本对象序列化?

6xfqseft  于 2022-12-24  发布在  TypeScript
关注(0)|答案(7)|浏览(528)

有什么方法可以对Typescript对象进行JSON序列化/反序列化,从而使它们不会丢失类型信息吗?简单的JSON.parse(JSON.stringify)有太多的警告。
或者我应该使用临时解决方案?

1bqhqjot

1bqhqjot1#

使用接口获取强类型:

// 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);

如果需要,可以使用类型Assert“〈〉”。

fcwjkofz

fcwjkofz2#

我认为处理这个问题的更好方法是使用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());

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

cetgtptt

cetgtptt3#

到目前为止,我发现最好的方法是使用"jackson-js". jackson-js是一个允许你使用ts装饰器描述类,然后序列化和去序列化保存类型信息的项目,它支持数组,Map等。
完整教程: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'
}
*/

有几个其他项目声称做同样的事情-

然而,jackson-js是我使用TypeScript Map时唯一有效的。

aiazj4mn

aiazj4mn4#

AQuirky answer对我来说很好用。你可能会在Object.assign方法上遇到一些麻烦。我不得不修改我的tsconfig.json以包括:

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

ac1kyiln5#

首先,需要创建源实体的接口,该接口以JSON形式从API接收:

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

其次,用构造函数实现模型,在构造函数中可以定制( Camel 化)一些字段名:

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

最后,使用JavaScript对象“jsonUser”创建用户模型的示例

const jsonUser = {name: 'Ted', age: 2, country_code: 'US'};

    const userInstance = new User(jsonUser);

    console.log({ userInstance })

这里是到Playground的链接。

zy1mlcev

zy1mlcev6#

我还建议使用ts-jackson
它是根据 typescript 构建的,允许解析深度嵌套的结构。

egmofgnx

egmofgnx7#

AQuirky的答案是一个很好的起点,但正如我在评论中提到的,它的主要问题是需要允许创建具有未定义字段的对象,然后由他的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
}

相关问题