Reputation: 2804
My app loads instances of reference data. Some of the instances have getters that use data from other reference data. Like this:
class Person{
name: string
cityId: number
get city(): City {
return City.all.get(this.cityId)!
}
}
As the reference data never changes, a call to a getter will always return the same result. So I would like to make a getter that replaces itself with its result. I was thinking of a decorator like this:
export const selfReplacing = <T>(target: T, propertyKey: keyof T, descriptor: PropertyDescriptor): any => {
const oldGetter = descriptor.get!
descriptor.get = function (this: T) {
const value = oldGetter.call(this)
Object.defineProperty(this, propertyKey, {
value,
enumerable: true
})
return value
}
}
Which I could use like this:
class Person{
name: string
cityId: number
@selfReplacing
get city(): City {
return City.all.get(this.cityId)!
}
}
Is this the best way to do it?
Upvotes: 1
Views: 20
Reputation: 222750
Redefining property descriptor on first property access is the best way to do that.
Alternatively, a value can be cached to local variable or, better, a property:
export const selfReplacing = <T>(target: T, propertyKey: keyof T, descriptor: PropertyDescriptor): any => {
const oldGetter = descriptor.get!
const cacheKey = Symbol(`${propertyKey} cache`);
descriptor.get = function (this: T) {
if (!(cacheKey in this))
this[cacheKey] = oldGetter.call(this);
return return this[cacheKey];
}
}
May be helpful if some caching strategy should be additionally implemented (cache expiration, etc).
Upvotes: 1