詳細ガイド
依存性の注入

DIの実践

このガイドでは、Angularにおける依存性の注入の追加機能について説明します。

@Injectを使用したカスタムプロバイダー

カスタムプロバイダーを使用すると、組み込みのブラウザAPIなど、暗黙的な依存関係に対して具体的な実装を提供できます。 次の例では、InjectionTokenを使用して、BrowserStorageService内の依存関係としてlocalStorageブラウザAPIを提供します。

src/app/storage.service.ts

      
import { Inject, Injectable, InjectionToken } from '@angular/core';
export const BROWSER_STORAGE = new InjectionToken<Storage>('Browser Storage', {
providedIn: 'root',
factory: () => localStorage
});
@Injectable({
providedIn: 'root'
})
export class BrowserStorageService {
constructor(@Inject(BROWSER_STORAGE) public storage: Storage) {}
get(key: string) {
return this.storage.getItem(key);
}
set(key: string, value: string) {
this.storage.setItem(key, value);
}
}

factory関数は、ブラウザのウィンドウオブジェクトに添付されているlocalStorageプロパティを返します。 Injectデコレーターは、storageコンストラクターパラメーターに適用され、依存関係のカスタムプロバイダーを指定します。

このカスタムプロバイダーは、実際のブラウザAPIと対話するのではなく、モックAPIのlocalStorageを使用してテスト中にオーバーライドできます。

コンポーネントのDOM要素を注入する

開発者は避けるように努めていても、一部の視覚効果とサードパーティツールでは、直接DOMにアクセスする必要があります。 そのため、コンポーネントのDOM要素にアクセスする必要がある場合があります。

Angularは、@Componentまたは@Directiveの基になる要素を、ElementRefインジェクショントークンを使用してインジェクションすることで公開します。

      
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private element: ElementRef) {}
update() {
this.element.nativeElement.style.color = 'red';
}
}

前方参照を使用して循環した依存関係を解決する

TypeScriptでは、クラスの宣言順序が重要です。 定義されるまでは、クラスを直接参照できません。

これは、特に推奨される1ファイルにつき1クラスルールに従っている場合は通常問題ありません。 しかし、循環参照は避けられない場合があります。 たとえば、クラス'A'がクラス'B'を参照し、'B'が'A'を参照する場合、いずれか一方を最初に定義する必要があります。

AngularのforwardRef()関数は、Angularが後で解決できる間接的な参照を作成します。

クラスが自分自身を参照する場合にも、同様の問題が発生します。 たとえば、providers配列内です。 providers配列は、@Component()デコレーター関数のプロパティであり、クラス定義の前に表示される必要があります。 forwardRefを使用して、このような循環参照を解消できます。

app.component.ts

      
providers: [
{
provide: PARENT_MENU_ITEM,
useExisting: forwardRef(() => MenuItem),
},
],