Typescript objects serialization?

Use Interfaces to get strong types:

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

And use type assertion "<>" if you need to.


I think a better way to handle this is to use Object.assign (which however requires ECMAScript 2015).

Given a class

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

Serialize and deserialize like this...

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

To take this example to the next level, consider nested objects...

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

Serialize and deserialize like this...

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

So unlike using an interface, this approach preserves methods.


The best method i found so far was to use "jackson-js", jackson-js is a project that allows you to describe the class using ts-decorators and then serialize and desirialize saving the type information. it supports arrays,maps etc.

full tutorial:https://itnext.io/jackson-js-powerful-javascript-decorators-to-serialize-deserialize-objects-into-json-and-vice-df952454cf

simple exmaple:

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'
}
*/

There are a few other projects that claim to do the same thing -

  • https://github.com/typestack/class-transformer
  • https://github.com/JohnWeisz/TypedJSON
  • https://www.npmjs.com/package/typescript-json-serializer
  • https://www.npmjs.com/package/ts-serializer

However jackson-js is the only one that worked for me when i used a Ts Map.


The AQuirky answer works for me. You may have some troubles with the Object.assign method. I had to modify my tsconfig.json to include:

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

First, you need to create an interface of your source entity which you receive from the API as JSON:

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

Second implement your model with constructor where you can customize (camelize) some field names:

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

Last create instance of your User model using JS object jsonUser"

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

    const userInstance = new User(jsonUser);
    
    console.log({ userInstance })

Result log

Here is the link to playground