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; };
}
いいえ、インターフェイスはDIではサポートされていません。 TypeScriptインターフェイスでは、実行時に静的にのみ使用できなくなるため、DIトークンとして使用できません。
または、キーまたはInjectionToken
として文字列を使用できます
provide('CoursesServiceInterface', {useClass: CoursesServiceMock}) // old
providers: [{provide: 'CoursesServiceInterface', useClass: CoursesServiceMock}]
のように注入します
constructor(@Inject('CoursesServiceInterface') private coursesService:CoursesServiceInterface) {}
インターフェイスを使用できない理由は、インターフェイスが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;
}
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;
}
これが役立つことを願っています。