Перейти к содержанию

Инъекция зависимостей в Angular

📅 30.09.2026

Инъекция зависимостей (DI) — шаблон проектирования: так организуют и делят код по приложению, передавая зависимости в класс снаружи, а не создавая их внутри.

Прежде чем читать это подробное руководство, загляните в «Основы» Angular.

По мере роста приложения одну и ту же функциональность приходится переиспользовать в разных частях кода. Инъекция зависимостей как раз для этого: зависимости передают классу, а не создают прямо внутри него. Части приложения проще переиспользовать и сопровождать.

Шаблон популярен, потому что закрывает типичные задачи:

  • Проще сопровождать код. Инъекция зависимостей разделяет ответственность: код легче рефакторить, повторов меньше.
  • Масштаб. Модульную функциональность можно переиспользовать в разных частях приложения, и расти проще.
  • Удобнее тестировать. В модульных тестах вместо настоящих реализаций при необходимости подставляют тестовые двойники.

Как устроена инъекция зависимостей в Angular?

Зависимость — любой объект, значение, функция или сервис, без которого класс не работает, но который он сам не создаёт. Его передают снаружи, и связь между частями приложения остаётся явной.

С системой инъекции зависимостей работают двумя способами:

  • Значения можно предоставить, то есть сделать доступными.
  • Эти значения можно внедрить, то есть запросить как зависимости.

Здесь «значения» — любые значения JavaScript: объекты, функции, экземпляры классов. Чаще всего внедряют такое:

  • Значения конфигурации: константы конкретного окружения, URL API, флаги функций и тому подобное.
  • Фабрики: функции, которые создают объекты или значения по условиям во время выполнения.
  • Сервисы: классы с общей функциональностью, бизнес-логикой или состоянием.

Компоненты и директивы Angular сами участвуют в DI: в них можно внедрять зависимости, и их самих можно отдавать для внедрения.

Что такое сервисы?

Сервис в Angular — класс TypeScript с декоратором @Service. Экземпляр такого класса внедряют как зависимость. Через сервисы чаще всего делят данные и функциональность по приложению.

Обычные виды сервисов:

  • Клиенты данных. Скрывают подробности запросов к серверу: и чтение, и изменение.
  • Управление состоянием. Задаёт состояние, общее для нескольких компонентов или страниц.
  • Аутентификация и авторизация. Ведёт аутентификацию пользователя, хранение токенов и контроль доступа.
  • Журнал и ошибки. Задаёт общий API для записи в журнал и для сообщений пользователю об ошибках.
  • События и рассылка. Обрабатывает события и уведомления, не привязанные к конкретному компоненту, либо рассылает их компонентам по паттерну «наблюдатель».
  • Вспомогательные функции. Переиспользуемые утилиты: форматирование данных, проверка, вычисления.

В примере объявлен сервис AnalyticsLogger:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import {Service} from '@angular/core';

@Service()
export class AnalyticsLogger {
  trackEvent(category: string, value: string) {
    console.log('Analytics event logged:', {
      category,
      value,
      timestamp: new Date().toISOString(),
    });
  }
}

@Service делает этот сервис синглтоном на всё приложение. Для большинства сервисов так и стоит делать.

Декоратор @Service — удобная краткая запись @Injectable({providedIn: 'root'}).

Внедрение зависимостей через inject()

Зависимости внедряют функцией inject() из Angular.

В примере панель навигации внедряет AnalyticsLogger и сервис Router: пользователь переходит на другую страницу, а событие при этом записывается.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import {Component, inject} from '@angular/core';
import {Router} from '@angular/router';
import {AnalyticsLogger} from './analytics-logger';

@Component({
  selector: 'app-navbar',
  template: `<a href="#" (click)="navigateToDetail($event)">Detail Page</a>`,
})
export class Navbar {
  private router = inject(Router);
  private analytics = inject(AnalyticsLogger);

  navigateToDetail(event: Event) {
    event.preventDefault();
    this.analytics.trackEvent('navigation', '/details');
    this.router.navigate(['/details']);
  }
}

Где можно вызывать inject()?

Зависимости внедряют при создании компонента, директивы или сервиса. Вызов inject стоит либо в constructor, либо в инициализаторе поля. Несколько обычных случаев:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Component(/* ... */)
export class MyComponent {
  // ✅ In class field initializer
  private service = inject(MyService);

  // ✅ In constructor body
  private anotherService: MyService;

  constructor() {
    this.anotherService = inject(MyService);
  }
}
1
2
3
4
5
@Directive({...})
export class MyDirective {
  // ✅ In class field initializer
  private element = inject(ElementRef);
}
1
2
3
4
5
6
7
8
import {Service, inject} from '@angular/core';
import {HttpClient} from '@angular/common/http';

@Service()
export class MyService {
  // ✅ In a service
  private http = inject(HttpClient);
}
1
2
3
4
5
export const authGuard = () => {
  // ✅ In a route guard
  const auth = inject(AuthService);
  return auth.isAuthenticated();
};

«Контекстом инъекции» в Angular называют любое место в коде, где можно вызвать inject. Чаще всего это создание компонента, директивы или сервиса; подробнее — в разделе контексты инъекции.

Подробнее — в документации API inject.

Следующие шаги

Когда основы инъекции зависимостей в Angular ясны, можно создавать свои сервисы.

Следующее руководство, Создание и использование сервисов, разбирает:

  • как создать сервис через Angular CLI или вручную;
  • как работает шаблон providedIn: 'root';
  • как внедрять сервисы в компоненты и другие сервисы.

Этого хватает для самого частого сценария сервисов в приложениях Angular.


Источник: https://angular.dev/guide/di

Комментарии