angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
95.88k stars 25.32k forks source link

Extending decorators doesn't work anymore with IVY #42924

Closed DanielKucal closed 3 years ago

DanielKucal commented 3 years ago

Which @angular/* package(s) are the source of the bug?

compiler

Is this a regression?

Yes

Description

Angular 11 introduced a requirement for abstract classes to be decorated by @Directive(). Using that decorator doesn't make sense as the parent class in most classes is not a directive and it conflicts with tslint's directive-class-suffix rule. That's just one use case for extending Angular decorator. With Angular 12 and IVY simple extend like this below won't work anymore:

export function AbstractClass() {
  return function (target: any) {
    return Directive()(target);
  }
}

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-ivy-3gwqzw?file=src%2Fapp%2Fapp.component.html

Please provide the exception or error you saw

Can't bind to '(property from parent class)' since it isn't a known property of '(actual class)'.
1. If 'text-input' is an Angular component and it has 'name' input, then verify that it is part of this module.
2. If 'text-input' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.

Please provide the environment you discovered this bug in

image

Anything else?

Any work-around?

JoostK commented 3 years ago

The AOT compiler is unable to process wrapped decorators, as it's unable to detect them statically. This has always been a constraint with the AOT compiler.

Using that decorator doesn't make sense as the parent class in most classes is not a directive and it conflicts with tslint's directive-class-suffix rule.

An abstract directive is not a directive in the sense that it cannot be used in a template (it doesn't have a selector) but it has all the behavior aspects of a directive like lifecycle hooks, inputs and outputs. Hence the design choice to use a directive decorator without selector (or without any argument) as the decorator to let a class be compiled as Angular class by the AOT compiler. Hiding the Directive decorator in a custom decorator is therefore troublesome, as the AOT compiler is unable to detect it then.

The abstract directive decorator has been deprecated in v9 and became required in v10 for applications (existing libraries that predate v10 continue to be migrated ad-hoc). As such, I wouldn't consider this a regression as the change has been intentional and dynamic decorators have never been supported by the AOT compiler.

Also see #35585.

alxhub commented 3 years ago

Joost is absolutely correct - closing as this is the intended behavior. I do believe the code you've shared will work with the Angular JIT compiler, as well.

DanielKucal commented 3 years ago

I disagree, JIT/AOT doesn't make any difference here, it's the IVY / View Engine thing that is relevant. Just disable IVY in the demo and it will work: https://stackblitz.com/edit/angular-ivy-iembcw?file=src%2Fapp%2Fapp.component.html Moreover, I have not been given any workaround - how to make the code that was working with View Engine make to work with IVY?

JoostK commented 3 years ago

If you switch the Stackblitz to VE it runs JIT mode, unlike Ivy which is AOT compiled by Stackblitz.

angular-automatic-lock-bot[bot] commented 3 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.