将 JSON.stringify 与 TypeScript getter/setter 结合使用
Using JSON.stringify in conjunction with TypeScript getter/setter
我在 TypeScript 中使用 getter/setter 访问器。由于变量和方法的名称不可能相同,因此我开始在变量前加上短划线,就像在许多示例中所做的那样:
private _major: number;
get major(): number {
return this._major;
}
set major(major: number) {
this._major = major;
}
现在当我使用 JSON.stringify() 方法将对象转换为 JSON 字符串时,它会使用变量名作为键:_major.
由于我不希望 JSON 文件的所有键都以小破折号为前缀,是否可以让 TypeScript 使用 getter 方法的名称(如果可用)?或者是否有任何其他方法可以使用 getter/setter 方法但仍然产生干净的 JSON 输出?
我知道有一些方法可以在 JSON 键写入字符串输出之前手动修改它们。我很好奇是否有更简单的解决方案。
Here is a JSFiddle 展示了当前的行为。
不,您不能让 JSON.stringify
使用 getter/setter 名称而不是 属性 名称。
但是你可以这样做:
class Version {
private _major: number;
get major(): number {
return this._major;
}
set major(major: number) {
this._major = major;
}
toJsonString(): string {
let json = JSON.stringify(this);
Object.keys(this).filter(key => key[0] === "_").forEach(key => {
json = json.replace(key, key.substring(1));
});
return json;
}
}
let version = new Version();
version.major = 2;
console.log(version.toJsonString()); // {"major":2}
我认为遍历属性和字符串操作是危险的。我会使用对象本身的原型,像这样:
public static toJSONString() : string {
return JSON.stringify(this, Object.keys(this.constructor.prototype)); // this is version class
}
基于@Jan-Aagaard 解决方案我已经测试了这个
public toJSON(): string {
let obj = Object.assign(this);
let keys = Object.keys(this.constructor.prototype);
obj.toJSON = undefined;
return JSON.stringify(obj, keys);
}
为了使用toJSON方法
我写了一个小库 ts-typed,它生成 getter/setter 用于运行时输入目的。我在使用 JSON.stringify() 时遇到了同样的问题。所以我通过添加一种序列化器解决了这个问题,并提议实现一种 toString(在 Java 中)购买调用它 toJSON。
这是一个例子:
import { TypedSerializer } from 'ts-typed';
export class RuntimeTypedClass {
private _major: number;
get major(): number {
return this._major;
}
set major(major: number) {
this._major = major;
}
/**
* toString equivalent, allows you to remove the _ prefix from props.
*
*/
toJSON(): RuntimeTypedClass {
return TypedSerializer.serialize(this);
}
}
旧问题的新答案。对于 getter/setter 没有私有字段的情况,或者私有字段名称与 getter/setter 不同的情况,我们可以使用 Object.getOwnPropertyDescriptors
来查找 get
方法来自原型。
我们在此处添加 toJSON
函数,以便它可以与其他发帖人提到的 JSON.stringify
一起使用。这意味着我们不能在 toJSON
内调用 JSON.stringify()
因为它会导致无限循环所以我们使用 Object.assign(...)
进行克隆
我还删除了 _private
字段作为整理措施。您可能想要删除不想包含在 JSON.
中的其他字段
public toJSON(): any {
//Shallow clone
let clone: any = Object.assign({}, this);
//Find the getter method descriptors
//Get methods are on the prototype, not the instance
const descriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf(this))
//Check to see if each descriptior is a get method
Object.keys(descriptors).forEach(key => {
if (descriptors[key] && descriptors[key].get) {
//Copy the result of each getter method onto the clone as a field
delete clone[key];
clone[key] = this[key]; //Call the getter
}
});
//Remove any left over private fields starting with '_'
Object.keys(clone).forEach(key => {
if (key.indexOf('_') == 0) {
delete clone[key];
}
});
//toJSON requires that we return an object
return clone;
}
不是动态的,但可以工作
export class MyClass{
text: string
get html() {
return this.text.toString().split("\n").map(e => `<p>${e}</p>`).join('');
}
toJson(): string {
return JSON.stringify({ ...this, html: this.html })
}
}
通话中
console.log(myClassObject.toJson())
我在 TypeScript 中使用 getter/setter 访问器。由于变量和方法的名称不可能相同,因此我开始在变量前加上短划线,就像在许多示例中所做的那样:
private _major: number;
get major(): number {
return this._major;
}
set major(major: number) {
this._major = major;
}
现在当我使用 JSON.stringify() 方法将对象转换为 JSON 字符串时,它会使用变量名作为键:_major.
由于我不希望 JSON 文件的所有键都以小破折号为前缀,是否可以让 TypeScript 使用 getter 方法的名称(如果可用)?或者是否有任何其他方法可以使用 getter/setter 方法但仍然产生干净的 JSON 输出?
我知道有一些方法可以在 JSON 键写入字符串输出之前手动修改它们。我很好奇是否有更简单的解决方案。
Here is a JSFiddle 展示了当前的行为。
不,您不能让 JSON.stringify
使用 getter/setter 名称而不是 属性 名称。
但是你可以这样做:
class Version {
private _major: number;
get major(): number {
return this._major;
}
set major(major: number) {
this._major = major;
}
toJsonString(): string {
let json = JSON.stringify(this);
Object.keys(this).filter(key => key[0] === "_").forEach(key => {
json = json.replace(key, key.substring(1));
});
return json;
}
}
let version = new Version();
version.major = 2;
console.log(version.toJsonString()); // {"major":2}
我认为遍历属性和字符串操作是危险的。我会使用对象本身的原型,像这样:
public static toJSONString() : string {
return JSON.stringify(this, Object.keys(this.constructor.prototype)); // this is version class
}
基于@Jan-Aagaard 解决方案我已经测试了这个
public toJSON(): string {
let obj = Object.assign(this);
let keys = Object.keys(this.constructor.prototype);
obj.toJSON = undefined;
return JSON.stringify(obj, keys);
}
为了使用toJSON方法
我写了一个小库 ts-typed,它生成 getter/setter 用于运行时输入目的。我在使用 JSON.stringify() 时遇到了同样的问题。所以我通过添加一种序列化器解决了这个问题,并提议实现一种 toString(在 Java 中)购买调用它 toJSON。
这是一个例子:
import { TypedSerializer } from 'ts-typed';
export class RuntimeTypedClass {
private _major: number;
get major(): number {
return this._major;
}
set major(major: number) {
this._major = major;
}
/**
* toString equivalent, allows you to remove the _ prefix from props.
*
*/
toJSON(): RuntimeTypedClass {
return TypedSerializer.serialize(this);
}
}
旧问题的新答案。对于 getter/setter 没有私有字段的情况,或者私有字段名称与 getter/setter 不同的情况,我们可以使用 Object.getOwnPropertyDescriptors
来查找 get
方法来自原型。
我们在此处添加 toJSON
函数,以便它可以与其他发帖人提到的 JSON.stringify
一起使用。这意味着我们不能在 toJSON
内调用 JSON.stringify()
因为它会导致无限循环所以我们使用 Object.assign(...)
我还删除了 _private
字段作为整理措施。您可能想要删除不想包含在 JSON.
public toJSON(): any {
//Shallow clone
let clone: any = Object.assign({}, this);
//Find the getter method descriptors
//Get methods are on the prototype, not the instance
const descriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf(this))
//Check to see if each descriptior is a get method
Object.keys(descriptors).forEach(key => {
if (descriptors[key] && descriptors[key].get) {
//Copy the result of each getter method onto the clone as a field
delete clone[key];
clone[key] = this[key]; //Call the getter
}
});
//Remove any left over private fields starting with '_'
Object.keys(clone).forEach(key => {
if (key.indexOf('_') == 0) {
delete clone[key];
}
});
//toJSON requires that we return an object
return clone;
}
不是动态的,但可以工作
export class MyClass{
text: string
get html() {
return this.text.toString().split("\n").map(e => `<p>${e}</p>`).join('');
}
toJson(): string {
return JSON.stringify({ ...this, html: this.html })
}
}
通话中
console.log(myClassObject.toJson())