将 Typescript class 转换为字符串,使用 getter 和 setter 而不是私有变量
Convert Typescript class to string, with getter and setter instead of private variables
我有以下 Typescript 代码:
class Foo {
private _id: number;
private _desc: string;
constructor(id: number, desc: string) {
this._id = id;
this._desc = desc;
}
public get id(): number {
return this.id;
}
public set id(value: number) {
this._id = value;
}
public get desc():string {
return this.desc;
}
public set desc(value: string) {
this._desc = value;
}
}
let foo = new Foo(1, 'something');
我想从 Typescript class 中获取一个字符串,我的意思是 getter 和 setter。然后我应该得到以下字符串:
{"id":1,"desc":"something"}
根据这个 我可以达到将以下方法添加到 class:
public toJSONString(): string {
return JSON.stringify(this, Object.keys(this.constructor.prototype));
}
有效。
如果 Typescript class 包含任何其他子 class。
则不起作用
所以如果我有以下代码:
class Foo {
private _id: number;
private _desc: string;
private _user: Bar;
constructor(id: number, desc: string, user: Bar) {
this._id = id;
this._desc = desc;
this._user = user;
}
public get id(): number {
return this._id;
}
public set id(value: number) {
this._id = value;
}
public get desc():string {
return this._desc;
}
public set desc(value: string) {
this._desc = value;
}
public get user(): Bar {
return this._user;
}
public set user(value: Bar) {
this._user = value;
}
public toJSONString(): string {
return JSON.stringify(this, Object.keys(this.constructor.prototype));
}
}
class Bar {
private _name: string;
private _surname: string;
constructor(name: string, surname: string) {
this._name = name;
this._surname = surname;
}
public get name(): string {
return this._name;
}
public set name(value: string) {
this._name = value;
}
public get surname():string {
return this._surname;
}
public set surname(value: string) {
this._surname = value;
}
}
let foo = new Foo(1, 'something', new Bar('foo', 'bar'));
如果我使用 toJSONString
方法,我会得到以下字符串:
{"id":1,"desc":"something","user":{}}
而不是这个:
{"id":1,"desc":"something","user":{ "name": "foo", "surname": "bar"}}
那么,我怎样才能从具有其他子 class 的 Typescript class 中获取字符串?
(如果你需要这里是第二个代码的playground for the first code and here is the playground)
这里有两点要记住:
当您定义 getter 和 setter 时,一旦转译为 Javascript,它们不会成为实例方法,而是使用 Object.defineProperty 添加到原型中。这意味着你不会简单地使用 JSON.stringify
得到它们
将替换数组传递给 JSON.stringify 并告诉它仅使用原型值可以完成这项工作,但它有点不适用于嵌套对象。事实是 JSON.stringify 将只解析具有该名称的属性,无论它位于对象结构中的什么位置。
例如
let a = {
user: "Foo",
data: {
name: "Bar"
}
};
JSON.stringify(a, ["user", "data"]);
将输出 {"user":"Foo","data":{}}
因为即使嵌套对象的键是 data
,对象本身也没有名为 user
或 data
的属性
但是
let a = {
user: "Foo",
data: {
user: "Bar"
}
};
JSON.stringify(a, ["user", "data"]);
将输出 {"user":"Foo","data":{"user":"Bar"}}
因为嵌套对象有一个名为 user
的属性,就像它的父对象一样
我认为这种行为可能会令人困惑,但可以通过创建一个方法来实现解决方案,该方法获取您感兴趣的所有对象的所有属性。我还没有在 Typescript 中找到一种方法来检查是否class 实现了一个接口(或扩展了一个 class)所以我不得不对我所知道的它的工作进行一些工作,即使它不是 "elegant".
abstract class Stringifyiable {
private isStringifyiable(value): boolean {
return value != null && (typeof value === 'object' || typeof value === 'function') && value['getJsonKeys'] && typeof value['getJsonKeys'] === 'function';
}
public getJsonKeys(): string[] {
let keys = Object.keys(this.constructor.prototype);
keys.forEach(key => {
if (this.isStringifyiable(this[key])) {
keys = keys.concat(this[key].getJsonKeys());
}
});
return keys;
}
public toJSONString(): string {
return JSON.stringify(this, this.getJsonKeys());
}
}
class Foo extends Stringifyiable {
private _id: number;
private _desc: string;
private _user: Bar;
constructor(id: number, desc: string, user: Bar) {
super();
this._id = id;
this._desc = desc;
this._user = user;
}
public get id(): number {
return this._id;
}
public set id(value: number) {
this._id = value;
}
public get desc():string {
return this._desc;
}
public set desc(value: string) {
this._desc = value;
}
public get user(): Bar {
return this._user;
}
public set user(value: Bar) {
this._user = value;
}
}
class Bar extends Stringifyiable {
private _name: string;
private _surname: string;
constructor(name: string, surname: string) {
super();
this._name = name;
this._surname = surname;
}
public get name(): string {
return this._name;
}
public set name(value: string) {
this._name = value;
}
public get surname():string {
return this._surname;
}
public set surname(value: string) {
this._surname = value;
}
}
let foo = new Foo(1, 'something', new Bar('foo', 'bar'));
//this will output {"id":1,"desc":"something","user":{"name":"foo","surname":"bar"}}
foo.toJSONString();
小心循环引用,因为它会进入无限循环(不过我相信它可以修复)。
我有以下 Typescript 代码:
class Foo {
private _id: number;
private _desc: string;
constructor(id: number, desc: string) {
this._id = id;
this._desc = desc;
}
public get id(): number {
return this.id;
}
public set id(value: number) {
this._id = value;
}
public get desc():string {
return this.desc;
}
public set desc(value: string) {
this._desc = value;
}
}
let foo = new Foo(1, 'something');
我想从 Typescript class 中获取一个字符串,我的意思是 getter 和 setter。然后我应该得到以下字符串:
{"id":1,"desc":"something"}
根据这个
public toJSONString(): string {
return JSON.stringify(this, Object.keys(this.constructor.prototype));
}
有效。
如果 Typescript class 包含任何其他子 class。
则不起作用所以如果我有以下代码:
class Foo {
private _id: number;
private _desc: string;
private _user: Bar;
constructor(id: number, desc: string, user: Bar) {
this._id = id;
this._desc = desc;
this._user = user;
}
public get id(): number {
return this._id;
}
public set id(value: number) {
this._id = value;
}
public get desc():string {
return this._desc;
}
public set desc(value: string) {
this._desc = value;
}
public get user(): Bar {
return this._user;
}
public set user(value: Bar) {
this._user = value;
}
public toJSONString(): string {
return JSON.stringify(this, Object.keys(this.constructor.prototype));
}
}
class Bar {
private _name: string;
private _surname: string;
constructor(name: string, surname: string) {
this._name = name;
this._surname = surname;
}
public get name(): string {
return this._name;
}
public set name(value: string) {
this._name = value;
}
public get surname():string {
return this._surname;
}
public set surname(value: string) {
this._surname = value;
}
}
let foo = new Foo(1, 'something', new Bar('foo', 'bar'));
如果我使用 toJSONString
方法,我会得到以下字符串:
{"id":1,"desc":"something","user":{}}
而不是这个:
{"id":1,"desc":"something","user":{ "name": "foo", "surname": "bar"}}
那么,我怎样才能从具有其他子 class 的 Typescript class 中获取字符串?
(如果你需要这里是第二个代码的playground for the first code and here is the playground)
这里有两点要记住:
当您定义 getter 和 setter 时,一旦转译为 Javascript,它们不会成为实例方法,而是使用 Object.defineProperty 添加到原型中。这意味着你不会简单地使用 JSON.stringify
得到它们
将替换数组传递给 JSON.stringify 并告诉它仅使用原型值可以完成这项工作,但它有点不适用于嵌套对象。事实是 JSON.stringify 将只解析具有该名称的属性,无论它位于对象结构中的什么位置。
例如
let a = {
user: "Foo",
data: {
name: "Bar"
}
};
JSON.stringify(a, ["user", "data"]);
将输出 {"user":"Foo","data":{}}
因为即使嵌套对象的键是 data
,对象本身也没有名为 user
或 data
的属性
但是
let a = {
user: "Foo",
data: {
user: "Bar"
}
};
JSON.stringify(a, ["user", "data"]);
将输出 {"user":"Foo","data":{"user":"Bar"}}
因为嵌套对象有一个名为 user
的属性,就像它的父对象一样
我认为这种行为可能会令人困惑,但可以通过创建一个方法来实现解决方案,该方法获取您感兴趣的所有对象的所有属性。我还没有在 Typescript 中找到一种方法来检查是否class 实现了一个接口(或扩展了一个 class)所以我不得不对我所知道的它的工作进行一些工作,即使它不是 "elegant".
abstract class Stringifyiable {
private isStringifyiable(value): boolean {
return value != null && (typeof value === 'object' || typeof value === 'function') && value['getJsonKeys'] && typeof value['getJsonKeys'] === 'function';
}
public getJsonKeys(): string[] {
let keys = Object.keys(this.constructor.prototype);
keys.forEach(key => {
if (this.isStringifyiable(this[key])) {
keys = keys.concat(this[key].getJsonKeys());
}
});
return keys;
}
public toJSONString(): string {
return JSON.stringify(this, this.getJsonKeys());
}
}
class Foo extends Stringifyiable {
private _id: number;
private _desc: string;
private _user: Bar;
constructor(id: number, desc: string, user: Bar) {
super();
this._id = id;
this._desc = desc;
this._user = user;
}
public get id(): number {
return this._id;
}
public set id(value: number) {
this._id = value;
}
public get desc():string {
return this._desc;
}
public set desc(value: string) {
this._desc = value;
}
public get user(): Bar {
return this._user;
}
public set user(value: Bar) {
this._user = value;
}
}
class Bar extends Stringifyiable {
private _name: string;
private _surname: string;
constructor(name: string, surname: string) {
super();
this._name = name;
this._surname = surname;
}
public get name(): string {
return this._name;
}
public set name(value: string) {
this._name = value;
}
public get surname():string {
return this._surname;
}
public set surname(value: string) {
this._surname = value;
}
}
let foo = new Foo(1, 'something', new Bar('foo', 'bar'));
//this will output {"id":1,"desc":"something","user":{"name":"foo","surname":"bar"}}
foo.toJSONString();
小心循环引用,因为它会进入无限循环(不过我相信它可以修复)。