Injeção de Dependência em TypeScript: um guia simples para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: O que é Injeção de Dependência e para que serve?

No mundo do desenvolvimento de software, frequentemente nos deparamos com situações em que uma classe (ou módulo) depende de outra. Por exemplo, a classe UserService pode usar a classe DatabaseService para salvar dados. A abordagem tradicional é criar uma instância de DatabaseService diretamente dentro de UserService. Isso leva a um forte acoplamento do código, dificultando seu teste, manutenção e extensão.

Injeção de Dependência (DI) é um padrão de projeto que resolve esse problema. Em vez de criar dependências dentro da classe, elas são "injetadas" externamente. Isso implementa o princípio da Inversão de Controle (IoC): não é a classe que gerencia suas dependências, mas o código externo (um contêiner ou a parte chamadora) que as fornece.

Neste artigo, vamos explorar como implementar a Injeção de Dependência em TypeScript com exemplos simples. Você aprenderá por que DI é considerada uma boa prática e como ela ajuda a escrever código limpo e testável.



Problema: Acoplamento rígido sem DI

Vamos começar com um exemplo que mostra como não escrever código. Imagine que temos um aplicativo que envia notificações para usuários.

// Sem Injeção de Dependênciaclass EmailService {    sendEmail(to: string, message: string): void {        console.log(`Enviando email para ${to}: ${message}`);        // ... lógica real de envio    }}

class NotificationService { private emailService: EmailService;

constructor() { // Problema: acoplamento rígido this.emailService = new EmailService(); }

notifyUser(userEmail: string, message: string): void { this.emailService.sendEmail(userEmail, message); }}

// Usoconst notifier = new NotificationService();notifier.notifyUser('user@example.com', 'Hello!');

Neste código, NotificationService está rigidamente acoplado a EmailService. E se quisermos enviar SMS ou notificações push? Teríamos que modificar o código de NotificationService. Além disso, testar NotificationService é difícil — não conseguimos substituir o EmailService real por um objeto mock.



Solução: Injeção de dependência via construtor

A maneira mais simples e comum de implementar DI é passar dependências através do construtor. Isso torna o código flexível e facilmente testável.

Primeiro, vamos definir uma interface para nosso serviço de notificações. Este é um passo fundamental: programamos no nível de abstrações, não de implementações concretas.

// Definindo uma interface para qualquer serviço de notificaçõesinterface INotificationService {    send(to: string, message: string): void;}

// Implementação para Emailclass EmailService implements INotificationService { send(to: string, message: string): void { console.log(`[EMAIL] Enviado para ${to}: ${message}`); }}

// Implementação para SMSclass SMSService implements INotificationService { send(to: string, message: string): void { console.log(`[SMS] Enviado para ${to}: ${message}`); }}

// Classe que usa DIclass UserNotifier { private notifier: INotificationService;

// A dependência é injetada através do construtor constructor(notifier: INotificationService) { this.notifier = notifier; }

notifyUser(userContact: string, message: string): void { this.notifier.send(userContact, message); }}

// Usoconst emailNotifier = new UserNotifier(new EmailService());emailNotifier.notifyUser('alice@example.com', 'Seu pedido está pronto!');

const smsNotifier = new UserNotifier(new SMSService());smsNotifier.notifyUser('+7-999-123-45-67', 'Código de confirmação: 1234');

Agora, UserNotifier não sabe qual serviço

Blogs

Book Recommendations