Angular How-to: Simplify Components with TypeScript Inheritance

Premier Developer


Laurie Atkinson, Senior Consultant, By moving shared functionality to a base component and assigning dependencies inside the body of the constructor, you can simplify child components.

If your Angular components contain identical or similar functionality and you find yourself copying and pasting that code, it makes sense to implement some class inheritance, which is available with TypeScript. And, you can simplify the child components even further by removing the dependencies from the parent constructor arguments and manually assigning them inside the constructor.

Create the base component

In this example, we have 2 services that are used in the base class and are assigned using dependency injection.


Inherit child component from base component

Note that our child component must pass all parent dependencies into the constructor to extend it.


As you can see, with a substantially complex base class, the child classes will potentially need to include a much longer list of all its parent’s dependencies. And if the parent introduces a new dependency, then all children must be updated. This may be fine, but if you want to simplify the child classes as much as possible, then take a look at this alternative.

Use a class to store the injector

This class will hold the module’s injector. It will be set once and retrieved whenever a component or service needs to get a service dependency.


After the module has been bootstrapped, store the module’s injector in the AppInjector class.


Use this injector class to assign dependencies

Now, we can modify the base component to remove all constructor arguments.


Inherit child component from base component

Now the child component only needs to use dependency injection for its own dependencies.


Use the power of polymorphism to maximize code reuse

For maximum reuse of code, do not limit the methods in the parent class to merely those with identical implementations. Maybe you can refactor a complex method into pieces where shared logic can be moved into the parent. Maybe a method shares most of the logic with another component, but a few pieces differ between components which could be implemented in each child.

TypeScript inheritance allows you to override a parent method in the child class and if the parent calls that method, the child’s implementation will be invoked. For example, follow the order of execution shown in this picture, starting with a call to methodA() in ChildComponent.


Here is a non-trivial code example to illustrate the power of this feature. This application contains many pages, each comprised of a form. All these form pages share the following functionality:

  • only allow editing if the user has permission
  • save changes via a call to an API service
  • prompt the user if attempting to navigate away and there are unsaved changes

Build a form base component


Build a specific form child component


As you proceed with your development, if you find yourself copying and pasting code, take a moment to see if some refactoring might be in order. Class inheritance can give you an opportunity to delete some code and that always feels good. Doesn’t it?


Leave a comment

  • Brian Dance
    Brian Dance

    Hi Laurie,
    l liked the post and implmented as you described, but I have an intermintent timing issue. In main.ts the call to:   platformBrowserDynamic().bootstrapModule(AppModule).then((moduleRef) => { 
    is not always called before the base component constructor is called.
    constructor(protected route: ActivatedRoute) {
    // call parent constructor
              const injector = AppInjector.getInjector(); 
              this.updateService = injector.get(UpdateService); 
              this.authorizationService = injector.get(AuthorizationService); 
    So the call to:
    const injector = AppInjector.getInjector();
    will return undefined. Then all my services are undefined. Changing the route then fixes the issue as the inject is now set. I have implemented exactly as you have indicated above. Am I missing something? Do you have any suggestions? I have the same issue running locally and in production.      

    • Avatar
      Oliver Meissner

      You can make AppInfo.getInjector() returning an Rx.ReplaySubject<Injector>:
      export class AppInjector { private static injector: Injector = undefined; private static subject = new ReplaySubject<Injector>();static setInjector(injector: Injector) { console.log(‘SET INJECTOR’); AppInjector.injector = injector;; }static getInjector(): ReplaySubject<Injector> { console.log(‘READING INJECTOR’); return AppInjector.subject; }}
      Then, in your Components Constructor subscribe to that Subject and wait for the Injector:
      AppInjector.getInjector() .pipe(take(1)) .subscribe((injector) => { this.dialogService = injector.get(DialogService); this.routerService = injector.get(Router); });

  • Avatar
    Raship shah

    This is a neat trick. It even works, until I run the unit test cases. Apparently, the injector or the services doesn’t get initialized before the component constructor get’s called. I’m using the replaysubject method: AppInjector.getInjector().pipe(take(1)).subscribe((injector) => { this.authService = injector.get(AuthService); }); in BaseComponent and when the child component calls the method: this.authService.isLoggedIn(); the unit test case fails, saying authservice is undefined.

    • Nick Fiorello
      Nick Fiorello

      Two points about this kind of inheritance…

      1. Just inject the injector and angular will do all the work for you, and even make sure you get the right injector if your module is lazy loaded

      … BaseComponent {
      constructor(injector: Injector) {

      2. Inheritance of anything other than simple components has some gotchas because the decorators do not get extended, and lifecycle hoooks must be explicitly called.

      @Component({ providers: [LocalService] })
      class BaseComponent implements OnInit {
      constructor(injector: Injector) {
      this.local = injector.get(LocalService);

      ngOnInit() { }

      class ExtendedComponent extends BaseComponent {
      constructor(injector) {
      super(injector); // <= No Provider for LocalService
      // ngOnInit will never be called…