Angular 4 AOT compiler does not support mixins

angular, angular-compiler-cli

Solution

The main problem here is that angular compiler has limited functionality.(read more in the docs)

AOT compiler uses metadata that is generated by MetadataCollector. It uses typescript object model(tree of `Node`)(that's why AOT can be used only with typescript) to gather all information that is necessary to produce `ngfactory` (in some cases also `ngsummary`) files.

The examples you provided are completely different for AOT compiler:

1) Custom decorator

@Mixin([BehaviorInjected])
export class FooComponent {}

Angular `MetadataCollector` will include `@Mixin` decorator in metadata of `FooComponent` symbol(item in `decorators` array) but it will be skipped when aot `StaticReflector` will call `simplify` since `Mixin` decorator is not registered in special map that includes only strictly defined decorators (source code)

Moreover if we even include it in that map it still won't be executed during aot compilation because it is only available for supported decorators.

2) Call custom function

export class HomePageComponent extends TaggedComponent(MyComponent) {

`MetadataCollector` will add `TaggedComponent` to metadata collection as symbol like `{__symbolic: 'error', message: 'Symbol reference expected'};` but it also will be skipped inside `StaticReflector`.

And as far as i know there is currently no solution to support it.

Problem

Sometimes I use Mixins to inject repeated functions like `slugUrl()`. But it doesn't work with angular 4 compiler. ``` export function Mixin(decorators: Function[]) { return function (classFn: Function) { decorators.forEach(decorator => { Object.getOwnPropertyNames(decorator.prototype).forEach(name => { classFn.prototype[name] = decorator.prototype[name]; }); }); }; } @Mixin([BehaviorInjected]) export class FooComponent { } ``` If I compile this code, compiler throws: Property 'ngClassControl' does not exist on type 'FooComponent'. Any ideas? Edit: Since there was someone who asked, here's another example using TS mixins that reproduces the issue, this time at template level. Components: ``` @Component({ selector: 'home-page', template: '<test [tag]="tag"></test>' }) export class HomePageComponent extends TaggedComponent(MyComponent) { public tag = 'hi there'; } @Component({ selector: 'test', template: '<div></div>' }) export class TestComponent extends TaggedComponent(MyComponent) {} ``` Mixins: ``` type Constructor<T> = new(...args: any[]) => T; export function TaggedComponent<T extends Constructor<{}>>(Base: T) { class TaggedBase extends Base { @Input() tag: string; }; return TaggedBase; } export class MyComponent { protected subscriptions: Subscription = new Subscription(); // ... } ``` Error: ERROR in Error: Template parse errors: Can't bind to 'tag' since it isn't a known property of 'test'. ("][tag]="tag">")

Original source