2022-03
Refresher: What is a decorator?
Decorators are functions which have four main capabilities when applied to a class or class element
Decorators receive the original value, and can replace it with another value that has the same shape.
function wrapMethod(m) {
return function() {
console.log('before');
m.call(this);
console.log('after');
}
}
class C {
@wrapMethod m() {
console.log('method');
}
}
(new C).m();
// before
// method
// after
Decorators can run code to initialize the decorated value per-instance.
function bound(m, context) {
context.addInitializer(function() {
this[context.name] =
this[context.name].bind(this);
});
}
class C {
x = 123;
@bound m() {
console.log(this.x)
}
}
const { m } = new C();
m(); // 123
Decorators can add metadata which is then readable by external code.
const MY_META = Symbol();
function addMeta(value) {
return function(m, context) {
context.setMetadata(MY_META, value);
}
}
@addMeta('class')
class C {
@addMeta('pub') x;
@addMeta('priv') #x;
}
C.prototype[Symbol.metadata][MY_META].own;
// 'class'
C.prototype[Symbol.metadata][MY_META].public.x;
// 'pub'
C.prototype[Symbol.metadata][MY_META].private[0];
// 'priv'
Decorators can provide access to the decorated value via `access` object
const EXPOSE = Symbol();
function expose(value, context) {
context.setMetadata(EXPOSE, context.access.get);
}
class C {
@expose x = 123;
@expose #x = 456;
}
const c = new C();
const meta = C.prototype[Symbol.metadata][EXPOSE];
meta.public.x.call(c);
// 123
meta.private[0].call(c);
// 456
`accessor` can be used to create automatic getters/setters on a fiel
class C {
@reactive accessor foo = 123;
}