Object.defineProperty on a prototype prevents JSON.stringify from serializing it Object.defineProperty on a prototype prevents JSON.stringify from serializing it typescript typescript

Object.defineProperty on a prototype prevents JSON.stringify from serializing it


You can define a toJSON() method on your prototype to customize how instances are serialized.

Class1.prototype.toJSON = function () {    return {        Name: this.Name    };};JSON.stringify(new Class1()); // Will be '{"Name":"test1"}'


If you like to push it forward, give a try to decorators proposal for TypeScript:

According to this proposal (https://github.com/wycats/javascript-decorators):

A decorator is:

  • an expression
  • that evaluates to a function
  • that takes the target, name, and property descriptor as arguments
  • and optionally returns a property descriptor to install on the target object

It goes like this (high level view):

Client code:

@serializable()class Person {    constructor(name: string) {      this._name = name;    }    private _name: string;    @serialize()    get name() {      return this._name;    }    @serialize('Language')    get lang() {      return 'JavaScript';    }}

Infrastructure:

const serialized = new WeakMap();export function serializable(name?: string) {    return function (target, propertyKey, descriptor) {        target.prototype.toJSON = function () {            const map = serialized.get(target.prototype);            const props = Object.keys(map);            return props.reduce((previous, key) => {                previous[map[key]] = this[key];                return previous;            }, {});        }    }}export function serialize(name?: string) {    return function (target, propertyKey, descriptor) {        let map = serialized.get(target);        if (!map) {            map = {};            serialized.set(target, map);        }        map[propertyKey] = name || propertyKey;    }}

UPDATE: I extracted this sample decorator into a repository at https://github.com/awerlang/es-decorators


Yes, it is by design.

As defined in ECMA, only own enumerable properties are serialized (stringify() is defined in terms of Object.keys(), among others).

Property accessors are defined on prototypes, both in TypeScript and ES6.

And answering your last question, that is the most eficient way to perform this operation.

Beside that, only a) defining an toJSON() to each object part of the serialization, or b) passing a replacer function/array as 2nd argument to JSON.stringify().

Whitelist properties from prototype:

JSON.stringify(instance, Object.keys(instance.constructor.prototype))