← Назад к вопросам

Что такое InjectionToken?

2.3 Middle🔥 202 комментариев
#JavaScript Core

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое 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 гарантированно уникален, что предотвращает конфликты имен
  • Гибкость — позволяет инжектить любые типы данных, не только экземпляры классов
  • Документирование — строковый параметр в конструкторе служит описанием токена

Распространенные сценарии использования

  1. Конфигурация приложения

    export const FEATURE_FLAGS = new InjectionToken<FeatureFlags>('feature.flags');
    
    // Использование в разных модулях
    @NgModule({
      providers: [
        { provide: FEATURE_FLAGS, useValue: { newUi: true, experimental: false } }
      ]
    })
    
  2. Сторонние библиотеки

    // Библиотека предоставляет токен для конфигурации
    export const LIB_CONFIG = new InjectionToken('my-lib.config');
    
    // Пользователь библиотеки настраивает ее
    providers: [
      { provide: LIB_CONFIG, useValue: { apiKey: 'xyz', logLevel: 'debug' } }
    ]
    
  3. Множественные реализации

    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 для не-классовых зависимостей, конфигураций и любых значений, которые могут меняться в зависимости от окружения или требуют гибкости в предоставлении различных реализаций. Это делает код более поддерживаемым, тестируемым и гибким.