Как работает внедрение зависимостей (Dependency Injection) в Angular?
Внедрение зависимостей
Dependency Injection (DI) в Angular — механизм, в котором класс не создаёт свои зависимости сам, а получает их от инжектора. Это упрощает тестирование и повторное использование.
Сервис и его регистрация
@Injectable({ providedIn: 'root' })
export class UserService {
getUser() { /* ... */ }
}providedIn: 'root' создаёт один экземпляр (singleton) на всё приложение; сервис попадает в сборку только если используется (tree-shakable).
Получение зависимости
Через конструктор или функцию inject():
@Component({ selector: 'app-profile', template: '' })
export class ProfileComponent {
private users = inject(UserService);
// или constructor(private users: UserService) {}
}Иерархия инжекторов
Инжекторы образуют дерево: корневой, модульный и инжекторы компонентов. Запрос зависимости идёт вверх по дереву до первого провайдера.
providersв@Componentсоздаёт отдельный экземпляр для компонента и его потомков.@Optional(),@Self(),@SkipSelf(),@Host()управляют поиском.
Токены и провайдеры
Зависимость идентифицируется токеном — обычно классом. Для значений и интерфейсов используют InjectionToken:
export const API_URL = new InjectionToken<string>('API_URL');
providers: [{ provide: API_URL, useValue: 'https://api.example.com' }]
const url = inject(API_URL);Виды провайдеров: useClass (подмена реализации), useValue, useFactory (создание по логике), useExisting (псевдоним).
Зачем это нужно
- Легко подменить зависимость в тестах (
TestBed.configureTestingModule({ providers: [...] })). - Единая точка конфигурации (URL API, фичефлаги).
- Управляемое время жизни экземпляров.
Коротко для собеседования
Angular создаёт зависимости инжектором и передаёт через конструктор или inject(). Провайдеры регистрируют на разных уровнях иерархии (root, компонент), значения без класса задают через InjectionToken.