将JSON.stringify与TypeScript getter / setter结合使用

时间:2016-10-17 07:15:37

标签: json 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演示了当前的行为。

5 个答案:

答案 0 :(得分:8)

基于@ 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方法

答案 1 :(得分:3)

不,你不能让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}

答案 2 :(得分:2)

我认为迭代属性和字符串操作是危险的。我会使用对象本身的原型,如下所示:

public static toJSONString() : string {
    return JSON.stringify(this, Object.keys(this.constructor.prototype)); // this is version class
}

答案 3 :(得分:0)

我已经编写了一个小型库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);
    }
}

答案 4 :(得分:0)

一个老问题的新答案。对于 getter/setter 没有私有字段的情况,或者私有字段名称与 getter/setter 不同的情况,我们可以使用 Object.getOwnPropertyDescriptors 从原型中查找 get 方法。

https://stackoverflow.com/a/60400835/2325676

我们在这里添加了 toJSON 函数,以便它与其他海报提到的 JSON.stringify 一起使用。这意味着我们不能在 JSON.stringify() 内调用 toJSON,因为它会导致无限循环,所以我们使用 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;
}