Closed justinfagnani closed 6 years ago
Given that classes are expressions, why would something like this not be sufficient?
function define(tagname, clazz) => {
customElements.define(tagname, clazz);
return clazz;
}
define('my-element', class MyElement extends HTMLElement {})
?
Or, in this specific case:
customElements.define('my-element', class MyElement extends HTMLElement {})
The decorator case still defines a symbol for the class. Maybe more clear with an export:
@define('my-element')
export class MyElement extends HTMLElement {}
Decorators this simple might seem too trivial, but they are possible to statically analyze, and arguably still have ergonomic benefit.
(EDIT: This is unrelated to your comment directly above, I hadn't checked to see if anything new came in before posting.)
I was about to reply that this would potentially suffer from some lispy )))))))
-ness after the class, you can avoid this in the same way as mixin thing you mentioned a while ago:
function decoratorA(Class) {...}
function decoratorB(Class) {...}
function decoratorC(Class) {...}
decoratorA(decoratorB(decoratorC(class MyElement extends HTMLElement {
...
}))) // <- line noise; tedious to match
function decorate(...args) {
let Class = args.pop();
while (args.length) {
Class = args.pop()(Class);
}
return Class;
}
decorate(decoratorA, decoratorB, decoratorC,
class MyElement extends HTMLElement {
...
}) // <- always one (
To export the symbol:
export const MyElement =
decorate(decoratorA, decoratorB, decoratorC,
class extends HTMLElement {
...
});
But, yes, this would imply that there's no canonical class decorator behavior and any static analysis tool would have to know about the specific implementation of decorators you're using.
Also, I don't think this can provide a generic static analysis tool any useful information: either the decorator's implementation must be known by that tool ahead of time - at which point that specific decorator has become part of the language itself - or the implementation isn't known and the analysis wouldn't be assisted by changing the syntax from wrapping with a function to decorating with a function. For example, if you were attempting to perform some kind of type checking, decorating with a function won't provide any special implication that the type signatures of the methods of the decorated class won't change if the decorator has the opportunity to arbitrarily change those methods.
Yes, a static analysis tool would have to know about the decorator, but decorator syntax is much more amenable to analysis. So the Polymer Analyzer, which looks for element declarations, need only look for class declarations decorated with @define
, rather than try to look for calls to customElements.define
, which may be called from another function.
Your example of composing decorator functions would fool most static analysis. In my experience with very similar metadata annotations in other languages, @foo
is more likely to be directly used in a manner that can be detected.
I'm doing a scrub of these bugs. Happy to say that this is still supported in the current version! You can include this registration in a class finisher function.
Registering classes/functions could often invoke a registration function at class definition time, but not modify the object, such as with web components: