TypeScript Academy · Урок

Внедрение через конструктор

Корректно внедряйте зависимости через конструкторы

Урок 2 из 413 шагов

«Внедрение через конструктор» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.

Подробно о внедрении через конструктор

Внедрение через конструктор объявляет каждую зависимость параметром конструктора. Объект полностью связывается в момент создания, поэтому обязательные зависимости невозможно забыть.

Свойства параметров

TypeScript позволяет за один шаг объявить и присвоить зависимость, используя модификатор доступа параметра. private readonly автоматически создаёт поле и присваивает ему значение.

interface Mailer { send(to: string, body: string): void; }
class Notifier {
  constructor(private readonly mailer: Mailer) {}
}

Зависимости на основе интерфейсов

Зависимость от интерфейса, а не от класса, отделяет потребителя от конкретной реализации. Можно передать любой объект, соответствующий интерфейсу.

interface Mailer { send(to: string, body: string): void; }
class SmtpMailer implements Mailer {
  send(to: string, body: string) { console.log("SMTP ->", to); }
}

Связывание в корне композиции

Место, где создаётся граф объектов, называется корнем композиции. Там Вы выбираете конкретные реализации и внедряете их.

class Notifier {
  constructor(private readonly mailer: Mailer) {}
  notify(to: string) { this.mailer.send(to, "hello"); }
}
const app = new Notifier(new SmtpMailer());
app.notify("a@b.com");

Замена реализаций

Поскольку зависимость представлена интерфейсом, можно передать совершенно другую реализацию, не изменяя Notifier. В этом и заключается основная гибкость, которую предоставляет DI.

class FakeMailer implements Mailer {
  sent: string[] = [];
  send(to: string) { this.sent.push(to); }
}
const fake = new FakeMailer();
new Notifier(fake).notify("x@y.com");
console.log(fake.sent); // ["x@y.com"]

Тестирование без реального ввода-вывода

Внедрение fake-почтового сервиса позволяет тесту проверить, что было бы отправлено, без отправки настоящего письма. Тест выполняется быстро, детерминированно и изолированно.

const fake = new FakeMailer();
new Notifier(fake).notify("test@site");
console.log(fake.sent.length === 1); // true

Несколько зависимостей

Указывайте столько зависимостей, сколько необходимо. Каждая из них явная, типизированная и обязательная, поэтому потребности класса сразу видны.

interface Logger { log(m: string): void; }
class Notifier {
  constructor(
    private readonly mailer: Mailer,
    private readonly logger: Logger,
  ) {}
}

readonly предотвращает переназначение

Объявление внедрённых полей как readonly не позволяет заменить их в течение жизненного цикла объекта, сохраняя его зависимости стабильными и предсказуемыми.

class Notifier {
  constructor(private readonly mailer: Mailer) {}
  // this.mailer = ... would be a compile error
}

Без скрытого создания внутри

Класс, использующий внедрение через конструктор, не должен создавать свои зависимости внутри. Все зависимости поступают через конструктор, поэтому связанность остаётся явной.

Обязательные и необязательные зависимости

Обязательные зависимости следует помещать в конструктор. Действительно необязательные зависимости могут по умолчанию использовать реализацию без действий, которая всё равно передаётся извне, а не создаётся внутри.

const noopLogger: Logger = { log() {} };
new Notifier(new SmtpMailer(), noopLogger);

Итоги преимуществ

Внедрение через конструктор делает зависимости явными, объекты полностью инициализированными, реализации взаимозаменяемыми, а тесты — простыми. Не зря это основной стиль DI.

Краткая проверка

Краткая проверка по этому уроку.

Итоги

Внедрение через конструктор объявляет зависимости как параметры, часто с модификатором private readonly, и типизирует их интерфейсом. Корень композиции выбирает реализации, а тесты передают подставные реализации. Объекты всегда полностью связаны, а зависимости можно заменять без изменения класса.

Можно начать бесплатно

Изучай TypeScript с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
101
Уроки
352

Часто задаваемые вопросы

Урок «Внедрение через конструктор» бесплатный?

Да — полный текст урока «Внедрение через конструктор» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.

Чему я научусь в уроке «Внедрение через конструктор»?

Корректно внедряйте зависимости через конструкторы Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать TypeScript Academy?

Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Внедрение через конструктор»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке TypeScript Academy?

Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы инверсии управления
  2. Внедрение через конструктор
  3. DI-контейнеры с InversifyJS
  4. Типобезопасные токены служб
← Назад к TypeScript Academy