2016-05-03 8 views
20

Angular2でインターフェイスを挿入する適切な方法があるのだろうか? (下を参照)angle2でインターフェイスを挿入することはできますか?

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

よろしくお願いいたします。

CoursesServiceInterfaceがインターフェイスとして実装されている場合は、活字体のコンパイラは "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; }; 
} 

答えて

39

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

別の方法としては、キーとして文字列を使用することができますかInjectionToken

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

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

のようにそれを注入します

ではJavaScript自体がないのインターフェイスを持ってbeacauseもhttps://angular.io/api/core/InjectionToken

+0

useClass:@Injectデコレータの助けを借りて、それ、私が行方不明になった何だった...あまりにも悪いことは公式のチュートリアル – Aligned

+1

ではありませんhttps://angular.io/docs/ts/最新/ cookbook/dependency-injection.html#!#usevalue –

2

使用OpaqueToken、インタフェースは、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; 
} 

私はこれが役立つことを願って。

+0

OpaqueTokenはAngular v5で廃止され、代わりに「InjectionToken'''が使用されます – Ryan

-2

フロントエンドデベロッパへの私の経験(Javaバックエンド開発から来ている)は以下の通りです。

私たちが 'インターフェース'について話しているのであれば、インターフェースを使用する主な原則は、インターフェースを提供する言語によって保証されることを強く期待しています。 「実装に反対のインターフェースに対するコード」はどちらですか?

これはtypescript/angular2によって保証されていないようです。 (彼らはまだ、言葉のインターフェイスを使用するべきではない、多分)。

(警告:私の回避策は上級ユーザーに醜いに見えることができるように、私はangular2を学んでいる):私の場合は何をした
コンポーネントA1は 成分Bが親を知っていて、上のメソッドを呼び出す必要があり、子コンポーネントB.
を持っています親。
したがって、コンポーネントBはそのコンストラクタ内のDependencyInjectionを介して親を受け取ります。

constructor(private a: A1Component) {} 

すべては問題ありません。
物事は複雑になります。
もう1つのコンポーネントA2は、compの親になることができます。 B.
理想IはBのA1とA2(これは、Javaの世界で自然になるであろう)の両方によって実現されるインタフェース(不実装)を注入しなければなりません。
Bよりもこのインターフェイスで動作します。必要であれば、例えばA2への型キャストは、彼が持っているインスタンスが本当にA2かどうかをBに知らせるでしょう。

私は無地のコンポーネント/クラスではなく、サービス(私はほとんどのソリューションは、サービスを指していることを確認)について話します。
は私が@Host()、@Injectable()、OpaqueToken、プロバイダを使用しようとしましたが、常にエラーが発生しました。最終的にはうまくいくように見えました。実際には、コンポーネントBに注入されたオブジェクトは親ではなく空のオブジェクトでした。おそらくプロバイダに誤って使用され、親オブジェクトを挿入する代わりに新しい空のオブジェクトが作成されました。私はインターフェイスを使用していない:私は最後でやった


私はA1とA2のための無地の基本クラスを作成した - のはABASEそれを呼びましょう。
コンポーネントBはこの基本クラスへの参照を保持します。

//BComponent: 
parent: ABase;  

constructor(@Optional parentA1: A1Component, @Optional parentA2: A2Component) { 
    if(parentA1) 
     this.parent = parentA1; 
    else 
     this.parent = parentA2 
} 

はい、それは奇妙な回避策は、ありませんうれしいです(Javaの世界の考え方から来て、私は同意) - しかし、私はちょうど時間が不足し、「インタフェースについてがっかりしました:リファレンスは、このようコンストラクタで設定されます'もの。インターフェースは、活字体設計時のアーティファクトであるので、あなたがインターフェイスを使用することはできません

22

理由があります。 JavaScriptにはインターフェイスがありません。 TypeScriptインターフェイスは、生成されたJavaScriptから消えます。実行時に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:

角の公式ドキュメントは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 }] 

必要なコンストラクタに設定オブジェクトを注入すると

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

この回答を見つけたAngular 4を対象としている方には、解決策2は間違いありません行く。この設定では、 'provider'を' {provide:APP_CONFIG、useClass:AppConfigMockClass} 'のようなものに変更するだけで、あらゆる種類のモッククラスをユニットテストなどのために注入できます。 – Weikardzaena

+1

これはすばらしいことです。インターフェイスと同じファイルにトークンを定義すると、不必要な警告が表示されることがあります。https://github.com/angular/angular-cli/issues/2034 – EvanM

+0

@Weikardzaenaテストのために、プロバイダを変更しますか実際のAppModuleでは、またはこれらはテスト自身(または環境、例えば、テスト、dev、prodを使用して)で設定できますか? – Ryan

関連する問題