Reputation: 751
I have looking at some example of the the ES.next decorators and noticed that it might be possible to make a decorator that gets applied as a factor function that takes arguments, or directly by omitting the ()
at the end at the same time.
I managed to get either styles to work separately, as a factory function @decorate(withArgs)
, or directly @decorate
, but not both!
Here's an example: https://github.com/jayphelps/core-decorators.js#deprecate-alias-deprecated
class foo {
@deprecate
foo() {}
@deprecate("with an optional string")
bar() {}
}
I tried to examine the source code mentioned above, but with my limited experience with decorators, I couldn't figure out how to set up something like that.
Here's how I managed to get @decorate
to work without using any arguments
function decorate(target, key, descriptor) {
// do some stuff and then return the new descriptor
}
and here's how I managed to get @decorate(args)
to work with arguments as a factory function:
function decorate(...args) {
return function(target, key, descriptor) {
// do some stuff using args and then return the new descriptor
}
}
As you can see, at the point it's either decorate foo()
or decorate(args) foo()
, not both.
Upvotes: 2
Views: 306
Reputation: 4675
When writing @decorator
the browser expects that the decorator function is called immediately, where as, when writing @decorator(args)
it expects that a factory is called first, which will return a decorator function.
Here's an example of a decorator i wrote that adds a state property to a class that is driven by redux
export default function state (defaultState) {
function reducer(state, action) {
if (!state) {
state = defaultState;
}
...
}
function decorator (target) {...}
// If 1st argument is a function, it means `@state` was written
if (typeof defaultState === 'function') {
let target = defaultState;
defaultState = {};
return decorator(target);
} else {
return decorator;
}
}
Do note, that the decorator in the example is a class decorator, which has a different signature
(target)
than the method decorator you are writing(target, key, descriptor)
The decorator can be used with or without a parameter
import state from './decorators/redux-state'
@state({
name: '',
})
class MyClass {
...
}
@state
class MyOtherClass {
constructor(state= {name: ''}) {
this.state = state;
}
...
}
Jay Phelps, is abstracting the logic of figuring out how the decorator was called in a decorate
utility function, and that makis his code harder to follow.
Hope this helps
Upvotes: 3