Is it possible to inject interface with angular2?

No, interfaces are not supported for DI. With TypeScript interfaces are not available at runtime anymore, only statically and therefore can't be used as DI tokens.

Alternatively you can use strings as keys or InjectionToken

provide('CoursesServiceInterface', {useClass: CoursesServiceMock}) // old

providers: [{provide: 'CoursesServiceInterface', useClass: CoursesServiceMock}]

and inject it like

constructor(@Inject('CoursesServiceInterface') private coursesService:CoursesServiceInterface) {}

See also https://angular.io/api/core/InjectionToken


The reason you can't use interfaces is because 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.


Solution 1:

The easiest solution is just to define an abstract class which implements the interface. Often, you need a abstract class anyway.

Interface:

import {Role} from "../../model/role";

export interface ProcessEngine {

     login(username: string, password: string):string;

     getRoles(): Role[];
}

Abstract Class:

import {ProcessEngine} from "./process-engine.interface";

export abstract class ProcessEngineService implements ProcessEngine {

    abstract login(username: string, password: string): string;

    abstract getRoles(): Role[];

}

Concrete Class:

import { Injectable } from '@angular/core';
import {ProcessEngineService} from "./process-engine.service";

@Injectable()
export class WebRatioEngineService extends ProcessEngineService {

    login(username: string, password: string) : string {...}

    getRoles(): Role[] {...}

}

Now you can define your provider like usual:

@NgModule({
      ...
      providers: [
        ...,
        {provide: ProcessEngineService, useClass: WebRatioEngineService}
      ]
})

Solution 2:

The official documentation of Angular suggest to use the InjectionToken, similar to OpaqueToken. Here is the Example:

Your interface and class:

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

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

Define your Token:

import { InjectionToken } from '@angular/core';

export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');

Register the dependency provider using the InjectionToken object, e.g in your app.module.ts:

providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]

Than you can inject the configuration object into any constructor that needs it, with the help of an @Inject decorator:

constructor(@Inject(APP_CONFIG) config: AppConfig) {
     this.title = config.title;
}

Alternate solution for angular 9

@Injectable()
export class TodoListPublicService implements TodoListService {
  getTodos(): Todo[] {
    const todos: Todo[] = [
      {
        title: 'get groceries',
        description: 'eggs, milk, etc.',
        done: false
      }
    ];

    return todos;
  }
}

create an abstract class

export interface Todo {
  title: string;
  description: string;
  done: boolean;
}

@Injectable()
export abstract class TodoListService {
  abstract getTodos(): Todo[];
}

Use in the component

providers: [
    { provide: TodoListService, useClass: TodoListPublicService }
  ]
export class TodoListComponent implements OnInit {
  todos: Todo[];

  constructor(private todoListService: TodoListService) { }

  ngOnInit() {
  }