38

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!

Chklang
  • 857
  • 1
  • 8
  • 17
  • Did you try just to add the HostListener without doing anything else ? –  Dec 19 '17 at 08:09

1 Answers1

65

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

JeanPaul A.
  • 3,613
  • 1
  • 20
  • 29
  • O_o I don't understand, yesterday that's not works... Ok, fine, it's perfect! – Chklang Dec 19 '17 at 09:51
  • 6
    The thing is that in case the abstract class is extending another class which is a component, then Angular will require to declare the class in a module, which will subsequently fail since you cannot declare abstract classes in Angular. :( – Alma Alma Apr 03 '18 at 12:34
  • @CaptainFogetti then there is any solution to over come? – k11k2 May 02 '18 at 09:51
  • @k11k2 there is not any that I am aware of. In the end I had to reorganize my code so that there is no Angular component in the parent hierarchy of the abstract class. Sadly Angular has it's shortcomings too :( – Alma Alma May 03 '18 at 03:38
  • 2
    @Walfrat you don't understand the discussion. There is no concrete component to inherit from. We are talking about an abstract superclass which cannot be annotated with the `@Component` annotation. And yes. Angular 4 smells sometimes, I'll give you that. But still it's a great framework despite it's shortcomings. – Alma Alma Jun 13 '18 at 14:01
  • It's great. But we should always use Directives for all these functionalities. Abstract class inheritance is good when we want to restrict component to implement/extends few methods/properties. – Shivang Gupta Jan 02 '19 at 07:18
  • Can you create tests for a class like this? – NicuVlad Oct 02 '19 at 13:37
  • 1
    +10 for the @Component decorator being unnecessary! Thanks! – Dustin Malone Sep 02 '20 at 02:24
  • Another related answer: https://stackoverflow.com/a/63126097/1589218 – Envil Nov 16 '20 at 16:10