web-dev-qa-db-fra.com

Est-il possible d'injecter une interface avec angular2?

je me demande s’il existe un moyen approprié d’injecter des interfaces dans Angular2? (cf. ci-dessous)

Je pense que cela est lié au décorateur manquant @Injectable () sur l'interface, mais il semble que cela ne soit pas autorisé.

Cordialement.

Lorsque CoursesServiceInterface est implémenté en tant qu'interface, le compilateur TypeScript déclare que "CoursesServiceInterface ne peut pas trouver le nom":

import {CoursesServiceInterface} from './CoursesService.interface';
import {CoursesService} from './CoursesService.service';
import {CoursesServiceMock} from './CoursesServiceMock.service';
bootstrap(AppComponent, [
  ROUTER_PROVIDERS, 
  GlobalService,
  provide(CoursesServiceInterface, { useClass: CoursesServiceMock })
  ]);

mais avec CoursesServiceInterface comme interface:

import {Injectable} from 'angular2/core';
import {Course} from './Course.class';
//@Injectable()
export interface CoursesServiceInterface {
    getAllCourses(): Promise<Course[]>;//{ return null; };
    getCourse(id: number): Promise<Course>;// { return null; };
    remove(id: number): Promise<{}>;// { return null; };
}

Lorsque le service est une classe, le compilateur TypeScript ne se plaint plus:

import {Injectable} from 'angular2/core';
import {Course} from './Course.class';
@Injectable()
export class CoursesServiceInterface {  
    getAllCourses() : Promise<Course[]> { return null; };
    getCourse(id: number) :Promise<Course> { return null; };
    remove (id: number) : Promise<{}> { return null; };
}
48
user1568220

Non, les interfaces ne sont pas prises en charge pour DI. Avec TypeScript, les interfaces ne sont plus disponibles au moment de l'exécution, uniquement en mode statique et ne peuvent donc pas être utilisées en tant que jetons DI.

Sinon, vous pouvez utiliser des chaînes comme clés ou InjectionToken

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

et l'injecter comme

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

Voir aussi https://angular.io/api/core/InjectionToken

76

La raison pour laquelle vous ne pouvez pas utiliser les interfaces est qu’une interface est un artefact au moment de la conception TypeScript. JavaScript n'a pas d'interfaces. L'interface TypeScript disparaît du code JavaScript généré. Il ne reste aucune information de type d'interface pour Angular à rechercher au moment de l'exécution.


Solution 1:

La solution la plus simple consiste simplement à définir une classe abstraite qui implémente l'interface. De toute façon, vous avez souvent besoin d’une classe abstraite.

Interface:

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

export interface ProcessEngine {

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

     getRoles(): Role[];
}

Classe abstraite:

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

export abstract class ProcessEngineService implements ProcessEngine {

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

    abstract getRoles(): Role[];

}

Classe de béton:

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[] {...}

}

Vous pouvez maintenant définir votre fournisseur comme d'habitude:

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

Solution 2:

La documentation officielle de Angular suggère d'utiliser le InjectionToken , similaire à OpaqueToken. Voici l'exemple:

Votre interface et classe:

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

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

Définissez votre jeton:

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

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

Enregistrez le fournisseur de dépendance à l'aide de l'objet InjectionToken, par exemple dans votre app.module.ts:

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

Ensuite, vous pouvez injecter l’objet de configuration dans n’importe quel constructeur qui en a besoin, avec l’aide d’un décorateur @Inject:

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

Utilisez OpaqueToken, les interfaces ne sont pas prises en charge par DI, car javascript n’a pas d’interface. Une façon de faire cela dans Angular 2 consiste à utiliser OpaqueToken. https://angular.io/docs/ts/latest/guide/dependency-injection.html

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

export let APP_CONFIG = new OpaqueToken('app.config');

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

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

J'espère que cela peut aider.

2
Celso Bring