Decorators should me "mixins"
saviski opened this issue · 3 comments
saviski commented
Decorator should be implemented as mixins
just like
constructor
@classDecorator class MyClass {}
const classDecorator = (Class) => class extends Class {
constructor(...args) {
super(...args)
// init some stuff
}
}
method
class MyClass {
@methodDecorator
method() {}
}
const methodDecorator = (Class, method) => class extends Class {
[method](...args) {
// can change args
let result = super[method](...args)
// can change result
return result
}
}
property
class MyClass {
@propertyDecorator property
}
const propertyDecorator = (Class, property) => class extends Class {
get [property]() {
return 'yeah'
}
set[property] {
// does something
}
}
parameter
class MyClass {
method(@argumentDecorator arg) {}
}
const argumentDecorator = (Class, method, index) => class extends Class {
[method](...args) {
if (typeof args[index] != 'string') throw 'not a string'
let result = super[method](...args)
return result
}
}
this way any decorator can redefine anything, another method, parameter, define a new constructor with arbitrary initializer code
it just works
@A
class cls {
@B prop;
@C method(@D arg) {}
}
would be converted into
let cls = class cls {
prop;
method(arg) {}
}
cls = B(cls, 'prop')
cls = D(cls, 'method', 0)
cls = C(cls, 'method')
cls = A(cls)
for example, there is nothing impeding a property decorator from redefining the constructor or another method
class MyClass {
@propertyDecorator property
}
const propertyDecorator = (Class, property) => class extends Class {
constructor(...args) {
super(...args);
this[property] = 'init value'
}
anotherMethod(...args) {
super.anotherMethod?.(...args)
return 'other value'
}
}
saviski commented
It even makes pipes people happy:
let cls = class cls {
prop;
method(arg) {}
}
|> B(#, 'prop')
|> D(#, 'method', 0)
|> C(#, 'method')
|> A(#)
ljharb commented
"a decorator can redefine anything" is something that implementors soundly rejected, so this is a nonstarter.