Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое InjectionToken в Angular
InjectionToken — это мощный механизм системы внедрения зависимостей (DI) в Angular, который позволяет создавать типизированные токены для провайдеров, особенно когда токеном должен быть не класс, а другие типы данных (строки, объекты, функции и т.д.).
Основная проблема, которую решает InjectionToken
В стандартном случае Angular DI использует класс в качестве токена для поиска зависимости:
// Стандартное использование класса как токена
@Injectable()
class MyService {
constructor() {}
}
@Component({
providers: [MyService] // MyService - и токен, и реализация
})
class MyComponent {
constructor(private myService: MyService) {} // DI найдет по классу MyService
}
Однако что если нам нужно заинжектить примитивное значение, конфигурационный объект или функцию? Использовать класс как токен не получится. Именно здесь на помощь приходит InjectionToken.
Создание и использование InjectionToken
// Создание токена для строкового значения
import { InjectionToken } from '@angular/core';
export const API_URL = new InjectionToken<string>('api.url');
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
// Интерфейс для типизации
interface AppConfig {
apiEndpoint: string;
timeout: number;
retryAttempts: number;
}
Регистрация провайдеров с InjectionToken
// В модуле или компоненте
@NgModule({
providers: [
// Предоставление строкового значения
{ provide: API_URL, useValue: 'https://api.example.com' },
// Предоставление объекта конфигурации
{ provide: APP_CONFIG, useValue: {
apiEndpoint: 'https://api.example.com',
timeout: 5000,
retryAttempts: 3
}},
// Использование фабричной функции
{ provide: APP_CONFIG, useFactory: () => {
return window.appConfig || {
apiEndpoint: 'https://api.default.com',
timeout: 3000
};
}}
]
})
export class AppModule {}
Получение зависимости через InjectionToken
@Component({
selector: 'app-example',
template: `<div>Component with injected tokens</div>`
})
export class ExampleComponent {
// Инжекция через конструктор
constructor(
@Inject(API_URL) private apiUrl: string,
@Inject(APP_CONFIG) private config: AppConfig
) {
console.log('API URL:', this.apiUrl);
console.log('Config:', this.config);
}
}
// Или в сервисе с фабричной функцией
@Injectable()
export class ApiService {
constructor(
@Inject(API_URL) private baseUrl: string,
private http: HttpClient
) {}
getData() {
return this.http.get(`${this.baseUrl}/data`);
}
}
Ключевые преимущества InjectionToken
- Типобезопасность — TypeScript может проверять типы, связанные с токеном
- Уникальность — каждый экземпляр InjectionToken гарантированно уникален, что предотвращает конфликты имен
- Гибкость — позволяет инжектить любые типы данных, не только экземпляры классов
- Документирование — строковый параметр в конструкторе служит описанием токена
Распространенные сценарии использования
-
Конфигурация приложения
export const FEATURE_FLAGS = new InjectionToken<FeatureFlags>('feature.flags'); // Использование в разных модулях @NgModule({ providers: [ { provide: FEATURE_FLAGS, useValue: { newUi: true, experimental: false } } ] }) -
Сторонние библиотеки
// Библиотека предоставляет токен для конфигурации export const LIB_CONFIG = new InjectionToken('my-lib.config'); // Пользователь библиотеки настраивает ее providers: [ { provide: LIB_CONFIG, useValue: { apiKey: 'xyz', logLevel: 'debug' } } ] -
Множественные реализации
export const LOGGER = new InjectionToken<Logger[]>('logger.token'); providers: [ { provide: LOGGER, useClass: ConsoleLogger, multi: true }, { provide: LOGGER, useClass: ApiLogger, multi: true } ]
Важные особенности
- Строка-описание — первый параметр конструктора помогает при отладке
- Generic тип — обеспечивает строгую типизацию
- Множественные провайдеры — работает с
multi: trueдля предоставления массивов значений - Дерево зависимостей — можно переопределять в дочерних инжекторах
InjectionToken стал стандартом в Angular вместо устаревшего OpaqueToken (Angular 2-4). Это более типобезопасное решение, которое полностью интегрировано с TypeScript системой типов.
На практике я рекомендую всегда использовать InjectionToken для не-классовых зависимостей, конфигураций и любых значений, которые могут меняться в зависимости от окружения или требуют гибкости в предоставлении различных реализаций. Это делает код более поддерживаемым, тестируемым и гибким.