Reputation: 1099
I want to create a set of generic methods that I would be using instead of backing fields for properties. I need to do some general stuff in the setter (call event emitters in Angular 5) and I don't want to write it every time.
I have tried these three things:
I can pass the property name as a string, but I would like to avoid that.
I also tried to work with Error.stack but the parsing of the stack trace would differ in different browsers and I don't like that.
When I try to use arguments.callee.caller
i get: 'caller',
'callee', and 'arguments' properties may not be accessed on strict
mode functions or the arguments objects for calls to them
.
Any other suggestions?
Example of usage below. Note the // somehow get calling property name
comment. In this example I would like there a code that returns "myProperty"
string.
class ApplicationComponent {
private readonly properties = new Map<string, any>();
protected getProperty<T>(): T {
const propertyName = // somehow get calling property name
return <T>this.properties[propertyName];
}
protected setProperty<T>(value: T): void {
const propertyName = // somehow get calling property name
const oldValue = <T>this.properties[propertyName];
if (oldValue === value) {
return;
}
this.properties[propertyName] = value;
const eventEmitter = this[`${propertyName}Change`];
if (eventEmitter != null && eventEmitter instanceof EventEmitter) {
eventEmitter.emit(value);
}
}
}
class SomeComponent extends ApplicationComponent {
get myProperty(): SomeType {
return this.getProperty();
}
set myProperty(value: SomeType) {
this.setProperty(value);
}
readonly myPropertyChange = new EventEmitter<SomeType>();
}
Upvotes: 2
Views: 2069
Reputation: 222319
Verbosity helps, because it's impossible to reliably get property name in such cases in production. If getProperty
and setProperty
should affect a particular property, they should accept property name as a parameter.
This is a good use case for property decorators. A decorator accepts class prototype
object and property name. It can then set property descriptor to whatever it needs:
function property(proto, key) {
Object.defineProperty(proto, key, {
get() {
return this.properties[key]
},
set(val) { ... }
});
}
class SomeComponent extends ApplicationComponent {
@property
myProperty: SomeType;
}
Upvotes: 1