Skip to main content
Deno 2 is finally here 🎉️
Learn more

superserial

Downloads Version License Language Typescript

After data transfer, when the object needs to be restored, JSON has many limitations. It does not support values such as Infinity and NaN, and does not provide circular references.

superserial provides serialization in any way you can imagine.

Usage

with Deno

import { Serializer } from "https://deno.land/x/superserial/mod.ts";

const serializer = new Serializer();

const nodes = [{ self: null as any, siblings: [] as any[] }, {
  self: null as any,
  siblings: [] as any[],
}];
nodes[0].self = nodes[0];
nodes[0].siblings = nodes;
nodes[1].self = nodes[1];
nodes[1].siblings = nodes;

const serialized = serializer.serialize(nodes);

console.log(serialized);
// [$1,$2];{"self":$1,"siblings":$0};{"self":$2,"siblings":$0}

with Node.js & Browser

Install

npm install superserial
import { Serializer } from "superserial";

// Usage is as above :-)

Index

Built-in Objects

Value Properties

  • NaN
  • Infinity, -Infinity
  • undefined
serializer.serialize({
  und: undefined,
  nan: NaN,
  inf: Infinity,
  ninf: -Infinity,
}); // {"und":undefined,"nan":NaN,"inf":Infinity,"ninf":-Infinity}

Fundamental Objects

  • Symbol

ETC

  • BigInt
  • Date
  • RegExp
  • Map
  • Set
const symbol = Symbol();
serializer.serialize({
  sym: symbol,
  bigint: 100n,
  date: new Date(),
  regex: /abc/gmi,
  map: new Map([["key1", "value1"], ["key2", "value2"]]),
  set: new Set([1, 2, 3, 4]),
});
// {"sym":$1,"bigint":100n,"date":$2,"regex":$3,"map":$4,"set":$5};Symbol();Date(1648740167514);/abc/gim;Map("key1"=>"value1","key2"=>"value2");Set(1,2,3,4)

Circular Reference

Existing JSON functions do not support circular references, but superserial has solved this problem.

const nodes = [{ self: null as any, siblings: [] as any[] }, {
  self: null as any,
  siblings: [] as any[],
}];
nodes[0].self = nodes[0];
nodes[0].siblings = nodes;
nodes[1].self = nodes[1];
nodes[1].siblings = nodes;

const serialized = serializer.serialize(nodes);

console.log(serialized);
// [$1,$2];{"self":$1,"siblings":$0};{"self":$2,"siblings":$0}

const deserialized = serializer.deserialize(serialized) as typeof nodes;

console.log(deserialized === deserialized[0].siblings); // true
console.log(deserialized[0] === deserialized[0].self); // true
console.log(deserialized === deserialized[1].siblings); // true
console.log(deserialized[1] === deserialized[1].self); // true

Circular Set & Map

const set = new Set();
set.add(set);

serializer.serialize(set); // Set($0)

const map = new Map();
map.set(map, map);

serializer.serialize(map); // Map($0=>$0)

Class Support

Classes contain methods, getters, etc., but JSON doesn’t fully support them. superserial includes features that make it easy to use.

The class to be used for deserialize is defined when the Serializer is created.

class TestUser {
  constructor(
    public name: string,
    public birth: number,
  ) {
  }

  get age() {
    return new Date().getFullYear() - this.birth;
  }
}

const serializer = new Serializer({ classes: { TestUser } });

Serializes the object and then deserializes it again. Since the original class object is converted as it is, all getters and methods can be used as they are.

const serialized = serializer.serialize(new TestUser("wan2land", 2000));
console.log(serialized);
// TestUser{"name":"wan2land","birth":2000}

const user = serializer.deserialize(serialized);
console.log(user); // TestUser { name: "wan2land", birth: 2000 }
console.log(user.age); // 22

toSerialize / toDeserialize

Private variables can be converted using two special symbols (toSerialize, toDeserialize).

import {
  Serializer,
  toDeserialize,
  toSerialize,
} from "https://deno.land/x/superserial/mod.ts";

class TestUser {
  static [toDeserialize](data: { name: string; serializedBirth: number }) {
    const user = new TestUser(data.name, 0);
    user.#_birth = data.serializedBirth;
    return user;
  }

  #_birth: number;

  constructor(
    public name: string,
    birth: number,
  ) {
    this.#_birth = birth;
  }

  getBirth() {
    return this.#_birth;
  }

  [toSerialize]() {
    return {
      name: this.name,
      serializedBirth: this.#_birth,
    };
  }
}

const serializer = new Serializer({ classes: { TestUser } });

const serialized = serializer.serialize(new TestUser("wan2land", 2000));
console.log(serialized);
// TestUser{"name":"wan2land","serializedBirth":2000}

const user = serializer.deserialize<TestUser>(serialized);
console.log(user); // TestUser { name: "wan2land" }
console.log(user.getBirth()); // 2000

TODO

  • function type