web-dev-qa-db-ja.com

Angle2でインターフェイスを挿入することは可能ですか?

angular2にインターフェイスを注入する適切な方法があるのだろうか? (下記参照)

これはインターフェースにない@Injectable()デコレータに関連していると思いますが、これは許可されていないようです。

よろしく。

CoursesServiceInterfaceがインターフェイスとして実装されると、TypeScriptコンパイラは「CoursesServiceInterfaceが名前を見つけられません」と文句を言います。

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

しかし、インターフェースとしてCoursesServiceInterfaceを使用する場合:

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; };
}

サービスがクラスの場合、TypeScriptコンパイラはもう文句を言いません。

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

いいえ、インターフェイスはDIではサポートされていません。 TypeScriptインターフェイスでは、実行時に静的にのみ使用できなくなるため、DIトークンとして使用できません。

または、キーまたはInjectionTokenとして文字列を使用できます

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

のように注入します

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

https://angular.io/api/core/InjectionToken も参照してください

76

インターフェイスを使用できない理由は、インターフェイスがTypeScriptデザイン時のアーティファクトであるためです。 JavaScriptにはインターフェースがありません。生成されたJavaScriptからTypeScriptインターフェイスが消えます。 Angularが実行時に検出するためのインターフェイスタイプ情報はありません。


解決策1:

最も簡単な解決策は、インターフェイスを実装する抽象クラスを定義することです。とにかく、多くの場合、抽象クラスが必要です。

インタフェース:

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

export interface ProcessEngine {

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

     getRoles(): Role[];
}

抽象クラス:

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

export abstract class ProcessEngineService implements ProcessEngine {

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

    abstract getRoles(): Role[];

}

コンクリートクラス:

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

}

これで、通常のようにプロバイダーを定義できます。

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

解決策2:

Angularの公式ドキュメントでは、OpaqueTokenに似た InjectionToken を使用することを提案しています。次に例を示します。

インターフェースとクラス:

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

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

トークンを定義します:

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

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

例えば、app.module.ts内のInjectionTokenオブジェクトを使用して、依存関係プロバイダーを登録します。

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

@Injectデコレータの助けを借りて、構成オブジェクトをそれを必要とする任意のコンストラクターに注入できます。

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

OpaqueTokenを使用してください。Javascript自体にはインターフェースがないため、インターフェースはDIでサポートされていません。 Angular 2でこれを行う1つの方法は、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;
}

これが役立つことを願っています。

2
Celso Bring