TypeScript Version: All
Currently getters are not called when an initialized Typescript object is serialized into JSON. While it is logical runtime behaviour of javascript, it feels not like the desired behaviour from a 'Typescript point of view', the transpiled Class behaves not as the getter implies, to be a public property of the class.
export class TestClass
{
private _value:string = "value";
get value():string
{
return this._value;
}
}
let obj = new TestClass();
console.log(JSON.stringify(obj)); //{"_value":"value"}
The outputted JSON contains the private value property: {"_value":"value"}, instead of an evaluated getter. {"value":"value"}
In order to fix this a toJSON method could be implemented:
export class TestClass
{
private _value:string = "value";
get value():string
{
return this._value;
}
public toJSON()
{
return {
value: this.value
};
}
}
let obj = new TestClass();
console.log(JSON.stringify(obj)); //{"value":"value"}
It is my suggestion that Typescript would automatically add a toJSON method on transpilation, if the following conditions apply:
toJSON method implemented in the class or its parent classes.The generated toJSON method could expose (optionally only) all public properties and getters.
What about those that don't want their getters called when serializing?
I realise that It could mean a BC-break in terms of exposing more data when serializing to JSON than in the current situation. In my opinion a getter is part of the public API of a class and in most situations it is a miss that a getter is not exposed.
If data should not be exposed, it should not be public.
TypeScript is JavaScript with types. There's no such thing as a "Typescript object", just a JavaScript object. See the design goals.
If data should not be exposed, it should not be public.
Being exposed and being in a situation where it is meaningful when serialized are two different things. Especially if there is not setter, therefore it is a read only property... Serializing in semantically meaningful and changing the default runtime behaviour of JavaScript for limited use cases... 馃槩
I handle it at runtime by using a general toJSON() function like this:
toJSON() {
const proto = Object.getPrototypeOf(this);
const jsonObj: any = Object.assign({}, this);
Object.entries(Object.getOwnPropertyDescriptors(proto))
.filter(([key, descriptor]) => typeof descriptor.get === 'function')
.map(([key, descriptor]) => {
if (descriptor && key[0] !== '_') {
try {
const val = (this as any)[key];
jsonObj[key] = val;
} catch (error) {
console.error(`Error calling getter ${key}`, error);
}
}
});
return jsonObj;
}
Most helpful comment
I handle it at runtime by using a general
toJSON()function like this: