TypeScript:使用Object.keys(this)循环Class的属性

时间:2018-04-16 09:09:28

标签: typescript

我想循环遍历类的属性以生成json表示。

Object.keys(this).forEach((key: keyof MyElement)总是会抛出错误: Argument of type '(key: "name" | "toJSON") => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'. Types of parameters 'key' and 'value' are incompatible. Type 'string' is not assignable to type "name" | "toJSON"'.

我该如何解决这个问题?

这是班级。

export class MyElement {

    private _name: string = '';

    get name(): string {
        return this._name;
    }

    set name(value: string) {
        this._name = value;
    }

    public toJSON = (): Object => {

        let json = {};

        Object.keys(this).forEach((key: keyof MyElement) => {  // Error: TS2345: Argument of type '(key: "name" | "toJSON") => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'.
        // Types of parameters 'key' and 'value' are incompatible. Type 'string' is not assignable to type "name" | "toJSON"'.

            const val = this[key];

            if (typeof val !== "function") {

                let newKey = key[0] === '_' ? key.slice(1) : key;
                json[newKey] = val;
            }
        });

        return json;
    }

}

2 个答案:

答案 0 :(得分:1)

将lambda的签名更改为与forEach签名兼容的内容:

Object.keys(this).forEach((key: string) => {
    // ...
})

根据您显示的代码,使用人工key: keyof MyElement并没有什么好处,所以只需使用TypeScript会喜欢的签名。

答案 1 :(得分:0)

问题是编译器无法知道forEach返回的唯一键也是MyElement的键。例如,您可以定义一个扩展MyElement并具有其他键的新类,或者您可以使用Object.assign()更新它。

因此,当您尝试访问forEach时,必须使this[key]获取字符串参数并执行适当的转换(否则,如果您设置了--noImplicitAny编译器选项,则会收到错误下标的结果是隐式any)。此外,json还需要一个索引签名,以便为其分配任意属性。

public toJSON = (): Object => {

    let json: { [key: string]: string } = {};

    Object.keys(this).forEach((key: string) => { 
        const val = (this as any)[key];
        if (typeof val !== "function") {

            let newKey = key[0] === '_' ? key.slice(1) : key;
            json[newKey] = val;
        }
    });

    return json;
}