Inheritance and dependency injection

Solution 1:

I could solve this by injecting MyService within each and every component and use that argument for the super() call but that's definetly some kind of absurd.

It's not absurd. This is how constructors and constructor injection works.

Every injectable class has to declare the dependencies as constructor parameters and if the superclass also has dependencies these need to be listed in the subclass' constructor as well and passed along to the superclass with the super(dep1, dep2) call.

Passing around an injector and acquiring dependencies imperatively has serious disadvantages.

It hides dependencies which makes code harder to read.
It violates expectations of one familiar with how Angular2 DI works.
It breaks offline compilation that generates static code to replace declarative and imperative DI to improve performance and reduce code size.

Solution 2:

Updated solution, prevents multiple instances of myService being generated by using the global injector.

import {Injector} from '@angular/core';
import {MyServiceA} from './myServiceA';
import {MyServiceB} from './myServiceB';
import {MyServiceC} from './myServiceC';

export class AbstractComponent {
  protected myServiceA:MyServiceA;
  protected myServiceB:MyServiceB;
  protected myServiceC:MyServiceC;

  constructor(injector: Injector) {
    this.settingsServiceA = injector.get(MyServiceA);
    this.settingsServiceB = injector.get(MyServiceB);
    this.settingsServiceB = injector.get(MyServiceC);
  }
}

export MyComponent extends AbstractComponent {
  constructor(
    private anotherService: AnotherService,
    injector: Injector
  ) {
    super(injector);

    this.myServiceA.JustCallSomeMethod();
    this.myServiceB.JustCallAnotherMethod();
    this.myServiceC.JustOneMoreMethod();
  }
}

This will ensure that MyService can be used within any class that extends AbstractComponent without the need to inject MyService in every derived class.

There are some cons to this solution (see Ccomment from @Günter Zöchbauer below my original question):

  • Injecting the global injector is only an improvement when there are several different services that need to be injected in many places. If you just have one shared service then it's probably better/easier to inject that service within the derived class(es)
  • My solution and his proposed alternative have both the disadvantage that they make it harder to see which class depends on what service.

For a very well written explanation of dependency injection in Angular2 see this blog post which helped me greatly to solve the problem: http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html

Solution 3:

Instead of injecting all the services manually I created a class providing the services, e.g., it gets the services injected. This class is then injected into the derived classes and passed on to the base class.

Derived class:

@Component({
    ...
    providers: [ProviderService]
})
export class DerivedComponent extends BaseComponent {
    constructor(protected providerService: ProviderService) {
        super(providerService);
    }
}

Base class:

export class BaseComponent {
    constructor(protected providerService: ProviderService) {
        // do something with providerService
    }
}

Service-providing class:

@Injectable()
export class ProviderService {
    constructor(private _apiService: ApiService, private _authService: AuthService) {
    }
}