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