Search code examples
angulartypescriptinheritancecomponentsabstract

Angular4 Components inheritance with abstract class


I want to define a base class for my components to share some features. So i've began with :

export abstract class BaseComponent {
    protected getName(): string;
}

@Component(...)
export class MyComponent extends BaseComponent {
    protected getName(): string {
        return "MyComponent";
    }
}

But after i needed to add some annotations to BaseComponent like @HostListener('window:keydown', ['$event']). So i had to add @Component to BaseComponent to enable angular annotations. Everything was good... Until i tried to compile in production mode with

ng build --prod

:

Cannot determine the module for class BaseComponent

So i've added BaseComponent to @NgModule, but i had :

No template specified for component BaseComponent

So i've added

@Component({template: ''})

But i had :

Argument of type 'typeof BaseComponent' is not assignable to parameter of type 'Type'. Cannot assign an abstract constructor type to a non-abstract constructor type.

So i had remove the "abstract" keyword to compile in production mode my project.

Do you have a solution? I dislike bad conception!


Solution

  • Update for Angular 10+

    As of Angular 10, when using the IVY compiler, components that are inherited, and which contain Angular functionality, must be decorated with an empty @Directive() decorator.

    Read more about it here


    There's no need to add @Component() annotations to abstract classes or register them to any module.

    It could be that there's something wrong within your code that does not conform to what Angular expects.

    I created a demo application using Angular CLI 1.2.7 with the ng new <name> command and extend the AppComponent class as below.

    base.component.ts

    import { HostListener } from '@angular/core';
    
    export abstract class BaseComponent {
        @HostListener('click')
        onClick() {
            alert('Click');
        }
    }
    

    and

    app.component.ts

    import { Component } from '@angular/core';
    import { BaseComponent } from './base.component';
    
    @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: [ './app.component.css' ]
    })
    export class AppComponent extends BaseComponent {
        title = 'app';
    }
    

    The app.module class was not changed in any way.

    The click handler located in the base component worked without any problems. A AOT compilation using ng build --prod also did not give any errors.

    This demo was using angular v5.1.1