とんかつ時々あんどーなつ

〜たとえ低空でも飛行していられるように〜

「Angular の依存性の注入」を読み直してみた

全部公式ドキュメントに書いてあるが、章立ても多くてまぁまぁな分量だったのでまとめた。

Angular の依存性の注入

  • サービス(@Injectable() デコレータが付与された class)は injector の範囲内でシングルトンインスタンスを提供する
    • injector の範囲内なのでアプリケーションでシングルトンとは限らない
    • アプリケーションは一つの root injector があるため root injector に登録された場合はアプリケーション全体でシングルトンインスタンスになる
  • @Injectable() デコレータがつくことで Angular は注入可能であることがわかる
  • ただし、provider で injector を設定するまで注入できない

provider のスコープ

  • providedIn: root: root injector に提供される → アプリケーション全体で使用できるようになる
  • AppModule でない NgModule の providers: [] 指定した場合はその module 内で使用できるようになる
  • component の provider 配列に追加するとスコープが対象の component とその子孫 component に限定される

依存関係 provider

  • 依存関係 provider は DI トークンを使って injector を設定する
  • 方法は下記のようにいくつかある

Class provider

  • 下記のように設定することで component が Logger トークンを使用して Logger を要求したときに Logger のインスタンスを返す
[{ provide: Logger, useClass: Logger }]
[NewLogger, { provide: OldLogger, useExisting: NewLogger}]

Value provider

  • class ではなく object を注入したい場合は useValue が使われることもある
export const SilentLogger = { logs: '', log: ''};
...
[{ provide: Logger, useValue: SilentLogger }]

class 以外を注入したい場合

  • class 以外にオブジェクトなども注入したいと思ったときはいくつか手順を踏む必要がある
  • 以下のような定数を注入したいとする
interface AppConfig {
  title: string;
};
export const DI_CONFIG: AppConfig = {
  title: 'Dependency Injection'
};
  • これは今までのように注入することはできない
// これはエラーになる
[{ provide: AppConfig, useValue: DI_CONFIG })]
  • Angular は interface を injection token として使用できないためである
  • そのため injection token を自分で作る必要がある
import { InjectionToken } from '@angular/core';
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
  • 作成した injection token を使えば provider に登録できる
providers: [{ provide: APP_CONFIG, useValue: DI_CONFIG }]
  • 注入するには以下のようにする
constructor(@Inject(APP_CONFIG) config: AppConfig) {
  this.title = config.title;
}

メモ

CLI でサービス作ると基本 providedIn: root になるから provider のスコープとか気にしてなかったが理解が深まった。(きっかけは https://ngrx.io/guide/component-store/read だったが)

大事なことは全部公式ドキュメントに書いてある。