JSON works fine for simple things, but sometimes my data has more types than JSON can handle. For example: Sets, UUIDs, Symbols, Dates, byte arrays, etc. Do I need to manually convert those to and from JSON, or is there a library or standard way of doing it?

I'm building a web app with Node.js on server and a fair amount of Javascript/Typescript in browser sending and receiving data.

1 Answers

1
Keith On

As I mention in comments, I'm not aware of any lib that does this out the box.

But a simple encode / decode to do this automatically is pretty easy to do, below I basically tag the objects key's with some simple type information, eg. "Date", "Sym", "Str" etc,.. Of course this is not complete you can extend for as many types as you like, but this hopefully will be a starting point.

Also it should be simple to make this do deep serialisation, I've kept it flat here to keep things simple. But if you do need nested serialisation, and need help just let us know.

const symbol1 = Symbol("symbol1");

//for symbols were going to need a lookup
//using a named symbol here would be best
//but remember Symbol("1") === Symbol("1") is false
const symLookup = {
  [symbol1.toString()] : symbol1
};

function encode(src) {
  return JSON.stringify(Object.entries(src).reduce(
    (a, [k, v]) => {
      if (v instanceof Date) {
        k = 'Date_' + k;
        v = v.getTime();
      } else if (v instanceof Set) {
        k = 'Set_' + k;
        v = Array.from(v);
      } else if (typeof v === 'string') {
        k = 'Str_' + k;
      } else if (typeof v === 'symbol') {
        k = 'Sym_' + k;
        v = v.toString()
      } else throw new Error("Not yet implemented");
      a[k] = v;
      return a;
    }, {}));
}

function decode(src) {
  const o = JSON.parse(src);
  const reS = /^(.+)_(.+)$/;
  return Object.entries(o).reduce(
    (a, [k, v]) => {
      const [, tp, k2] = reS.exec(k);
      if (tp === 'Date') v = new Date(v);
      else if (tp === 'Set') v = new Set(v);
      else if (tp === 'Sym') v = symLookup[v];
      a[k2] = v;
      return a;
    }, {});
}


const data = {
  theDate: new Date(),
  aSet: new Set([1,2,3]),
  justAString: "Hello there",
  sym: symbol1
}

console.log('src data = '); console.log(data);
var encoded = encode(data);
console.log('encoded data = '); console.log(encoded);
var decoded = decode(encoded);
console.log('decoded data = '); console.log(decoded);
<p>Look in browsers console to see results..</p>