I\'m using TypeScript to define some classes and when I create a property, it generates the equivalent to Class1
in the following plunkr:
http://plnkr.c
As you've discovered, it won't serialize properties defined on prototype.
I know it's not ideal, but another option is to do this:
class Class1 {
private _name = "test1";
Name: string; // do this to make the compiler happy
constructor() {
Object.defineProperty(this, "Name", {
get: function() { return this._name; },
set: function(value) { this._name = value; },
enumerable: true
});
}
}
Defining the property on the instance will serialize the property.
Put something here hopefully can help others. What I have do for fix JSON.stringify not serialize properties defined on prototype
var newObject = $.extend(false, {}, orginalObj);
then I notice newObject have instance properties instead of prototype properties. I'm use typescript and get accessor.
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:
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))