Consider this class:
export const CreditRiskRatingKeys: (keyof CreditRiskRating)[] =
[
'applicant_id',
'is_dirty'
];
export class CreditRiskRating {
applicant_id: string = '';
is_dirty: boolean = false;
fillQuestionDictionaryToModel() {
for (const key of CreditRiskRatingKeys) {
this[key] = 'test' as any ; // Error: Type 'any' is not assignable to type 'never'
}
}
}
Key
is already keyof CreditRiskRating
and this
is referring to the same class. Then why this[key] = 'test';
should complain?? What am I missing here?
Playground
5
TypeScript does not analyze the value types of the properties defined in your CreditRiskRatingKeys
to try to figure out whether you’re assigning the right value type to a given property.
One solution is to introduce a Property
type that restricts the value types of the listed properties:
export type Property<T, U> = {
[K in keyof T]: T[K] extends U ? K : never
}[keyof T];
export const CreditRiskRatingKeys: Property<CreditRiskRating, string>[] = [
'applicant_id'
] as const;
export class CreditRiskRating {
applicant_id: string = '';
fillQuestionDictionaryToModel() {
let f = this[CreditRiskRatingKeys[0]];
for (const key of CreditRiskRatingKeys) {
this[key] = 'test';
}
}
}
Playground link
2
The type keyof CreditRiskRating
is not only applicant_id
but also fillQuestionDictionaryToModel
. There’s no real distinction between methods and properties in JS.
So eventhough CreditRiskRatingKeys
is an array with only the value applicant_id
, according to the type it can be an array with 'applicant_id'
and/or 'fillQuestionDictionaryToModel'
. Thus typeof this[key]
can either be a string or a function () => void
.
To solve this, you can create a new utility type PropertyOf
that excludes methods:
type PropertyOf<T> = {
[K in keyof T]: T[K] extends Function ? never : K
}[keyof T];
and use it as
export const CreditRiskRatingKeys: PropertyOf<CreditRiskRating>[] = [
'applicant_id'
];
export class CreditRiskRating {
applicant_id: string = '';
fillQuestionDictionaryToModel() {
for (const key of CreditRiskRatingKeys) {
this[key] = 'test';
}
}
}
2