Angular 2 Interface Dependency Injection

December 2, 2016    JavaScript Development Angular2

Angular 2 Interface Dependency Injection

I want to be able to switch between my EnergyDataJSONService, EnergyDataService (which will call the real HTTP api), or a test data service in the app.module.ts or in a spec. The Angular 2 guide on Dependency Injection has shows that we need to use an OpaqueToken for interface based injection.

It says “TypeScript interfaces aren’t valid tokens… That seems strange if we’re used to dependency injection in strongly typed languages, where an interface is the preferred dependency lookup key. It’s not Angular’s fault. An interface is a TypeScript design-time artifact. JavaScript doesn’t have interfaces. The TypeScript interface disappears from the generated JavaScript. There is no interface type information left for Angular to find at runtime.”

I wish Angular could handle this for me, but I understand there are difficulties.

The Angular 2 guide only shows an example that exports a const. That’s great, but I need to use a real class.

`export interface AppConfig {
    apiEndpoint: string;
    title: string;
 }

export const HERO_DI_CONFIG: AppConfig = {
    apiEndpoint: 'api.heroes.com',
    title: 'Dependency Injection'
};`

Here is my solution. Thank you to Günter Zöchbauer and his answer on StackOverflow. Also see the Angular 2 cookbook.

My example is the IEnergyDataService that the EnergyDataService and EnergyDataJsonService. See the energy/energy-data-service.token.ts.

`import { OpaqueToken } from [email protected]/core';
 export let IEnergyDataServiceToken = new OpaqueToken('./energy-data-service.interface');`

app.module.ts has

`import EnergyDataJsonService from './energy/energy-data-json.service';
 import {IEnergyDataServiceToken} from './energy/energy-data-service.token';
 ....
 providers: [{ provide: IEnergyDataServiceToken, useClass: EnergyDataJsonService }]`

and energy/energy.component.ts gets the token injected

`import {IEnergyDataService} from './energy-data-service.interface';
 import {IEnergyDataServiceToken} from './energy-data-service.token';
 ...
 constructor(@Inject(IEnergyDataServiceToken) private energyDataService: IEnergyDataService, private router: Router) {}`

Please note the component’s usage of @Inject, the energy-data-service.token.ts for the OpaqueToken usage, and the providers array in app.module.ts.

I’m using "@angular/common": "2.2.1"



comments powered by Disqus