Injeção de Dependência (Dependency Injection) em TypeScript: Guia Completo

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 à Dependency Injection em TypeScript



Dependency Injection (DI) é um dos padrões de design chave que permite criar aplicações fracamente acopladas, testáveis e facilmente mantíveis. No contexto do TypeScript, graças à tipagem estrita e aos recursos de decoradores, a implementação de DI torna-se especialmente elegante e segura.



Neste artigo, veremos o que é Dependency Injection, como implementá-la em TypeScript e quais ferramentas podem simplificar esse processo. Você aprenderá como a DI ajuda a combater acoplamentos rígidos entre classes e torna seu código mais flexível.



O que é Dependency Injection e para que serve?



Dependency Injection (injeção de dependências) é um padrão no qual um objeto recebe suas dependências externamente, em vez de criá-las por conta própria. Isso implementa o princípio Inversion of Control (IoC) — inversão de controle.



Problema sem DI:

class Logger {    log(message: string): void {        console.log(message);    }}

class UserService { private logger: Logger;

constructor() { this.logger = new Logger(); // Acoplamento rígido }

createUser(name: string): void { this.logger.log(`User ${name} created`); }}


Neste exemplo, UserService está rigidamente acoplado a uma implementação específica de Logger. Se quisermos substituir o logger por, digamos, um de arquivo ou remoto, teremos que modificar o código de UserService.



Solução com DI:

interface ILogger {    log(message: string): void;}

class ConsoleLogger implements ILogger { log(message: string): void { console.log(message); }}

class FileLogger implements ILogger { log(message: string): void { // Escrita em arquivo }}

class UserService { constructor(private logger: ILogger) {} // Dependência injetada

createUser(name: string): void { this.logger.log(`User ${name} created`); }}

// Usoconst service = new UserService(new ConsoleLogger());


Vantagens da DI:

  • Testabilidade — facilidade para substituir dependências reais por objetos mock.
  • Flexibilidade — é possível alterar o comportamento do sistema sem modificar o código das classes.
  • Separação de responsabilidades — as classes não cuidam da criação de suas dependências.
  • Reutilização — as dependências podem ser usadas em diferentes partes da aplicação.


Implementação manual de Dependency Injection em TypeScript



A maneira mais simples é injetar dependências através do construtor ou de propriedades. O TypeScript, com suas interfaces e modificadores de acesso, torna isso muito conveniente.



Injeção via construtor (Constructor Injection)

interface IRepository<T> {    getAll(): Promise<T[]>;    getById(id: number): Promise<T | null>;}

class UserRepository implements IRepository<User> { async getAll(): Promise<User[]> { // Lógica real de trabalho com BD return []; }

async getById(id: number): Promise<User | null> { return null; }}

class UserController { constructor( private repository: IRepository<User>, private logger: ILogger ) {}

async getUsers(): Promise<User[]> { this.logger.log('Fetching users...'); return this.repository.getAll(); }}

// Criação do grafo de dependênciasconst logger = new ConsoleLogger();const repository = new UserRepository();const controller = new UserController(repository, logger);


Injeção via propriedades (Property Injection)

class EmailService {    private sender!: ISender;

setSender(sender: ISender): void {

Blogs

Book Recommendations