TypeScript: Løp gjennom egenskapene til en klasse med Object.keys(this)


Jeg vil gå gjennom egenskapene til en klasse for å generere en JSON-representasjon.

Object.keys(this).forEach((key: keyof MyElement) kaster alltid en feil: Argument of type '(key: "name" | "toJSON") => void' er ikke tildelbar til parameter av typen '(value: string, index: number, array: string[]) => void'. Typene til parameterne 'key' og 'value' er inkompatible. Type 'string' kan ikke tildeles typen "name" | "toJSON"'.

Hvordan kan jeg løse dette?

Her er klassen.

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;
    }

}

Svar #1

Endre lambdas signatur til noe som er kompatibelt med forEachs signatur:

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

Basert på koden du har vist, er det ingen reell fordel med å bruke den kunstige key: keyof MyElement, så bruk bare en signatur som TypeScript vil like.

Svar #2

Problemet er at det ikke finnes noen måte for kompilatoren å vite at de eneste nøklene som returneres av forEach også er nøkler i MyElement. For eksempel kan du definere en ny klasse som utvider MyElement og har flere nøkler, eller du kan ha oppdatert den med Object.assign().

Så du må få forEach til å ta en strengparameter og utføre passende typekonvertering når du prøver å få tilgang til this[key] (ellers, hvis du har --noImplicitAny kompilatoralternativet satt, vil du få en feil fordi resultatet av indeksering implisitt er any). Også json vil trenge en indeks-signatur for å la deg tilordne den vilkårlige attributter.

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;
}

Relaterte artikler