博客 / 詳情

返回

Angular 為什麼要引入 injection token 的概念

你可以定義和使用一個 InjectionToken 對象來為非類的依賴選擇一個提供者令牌。

這裏的重點是:非類。

下列例子定義了一個類型為 InjectionToken 的 APP_CONFIG .

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

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

這裏的 APP_CONFIG 只是一個令牌 token,或者説是一個 place holder.

可選的參數 <AppConfig> 和令牌描述 app.config 指明瞭此令牌的用途。
接着,用 APP_CONFIG 這個 InjectionToken 對象在組件中註冊依賴提供者。

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

語義是,消費者代碼裏,注入 APP_CONFIG 的令牌,則運行時,令牌會被實際的值 HERO_DI_CONFIG 取代。這個 HERO_DI_CONFIG 不是一個 Angular class, 所以只能以 injection token 的方式註冊提供者。

現在,藉助參數裝飾器 @Inject(),你可以把這個配置對象注入到構造函數中。

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

接口和依賴注入

雖然 TypeScript 的 AppConfig 接口可以在類中提供類型支持,但它在依賴注入時卻沒有任何作用。在 TypeScript 中,接口是一項設計期工件,它沒有可供 DI 框架使用的運行時表示形式或令牌。

當轉譯器把 TypeScript 轉換成 JavaScript 時,接口就會消失,因為 JavaScript 沒有接口。

由於 Angular 在運行期沒有接口,所以該接口不能作為令牌,也不能注入它。

因此,下列的代碼是不合法的:

// Can't use interface as provider token
[{ provide: AppConfig, useValue: HERO_DI_CONFIG })]

我們不能把 interface 本身作為一個令牌,因此 Angular 引入了 injection token 的概念。

同樣,下列的代碼亦不合法,因為 interface 不能作為構造函數的輸入參數類型注入。因此我們需要 @Inject, 將 interface 包裹一層之後再傳入構造函數。

// Can't inject using the interface as the parameter type
constructor(private config: AppConfig){ }
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.