Event Bus e padrão Observer em TypeScript: implementação e exemplos

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

Event Bus e padrão Observer em TypeScript: da teoria à prática



O desenvolvimento web moderno exige uma arquitetura flexível e escalável. Dois padrões-chave que ajudam a organizar a interação entre componentes são o Event Bus e o Observer. Neste artigo, analisaremos sua implementação em TypeScript, vantagens e cenários práticos de uso.



O que é o padrão Observer?



O padrão Observer (Observador) é um padrão de design comportamental que define uma dependência "um para muitos" entre objetos. Quando um objeto (publicador) altera seu estado, todos os objetos dependentes (assinantes) são automaticamente notificados e atualizados.



Elementos principais do padrão:

  • Subject (Publicador) — objeto que monitora alterações e notifica os assinantes.
  • Observer (Observador) — objeto que se inscreve nas alterações do publicador.
  • Event Bus (Barramento de Eventos) — mecanismo centralizado que gerencia assinaturas e o envio de eventos entre componentes.


Implementação do Event Bus em TypeScript



TypeScript oferece excelentes recursos para tipagem estrita, tornando a implementação do Event Bus segura e previsível. Vamos considerar uma implementação básica:



type EventHandler<T = any> = (payload: T) => void;

class EventBus { private listeners: Map<string, EventHandler[]> = new Map();

// Inscrição em um evento subscribe<T>(event: string, handler: EventHandler<T>): void { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event)!.push(handler); }

// Cancelamento de inscrição unsubscribe<T>(event: string, handler: EventHandler<T>): void { const handlers = this.listeners.get(event); if (handlers) { this.listeners.set( event, handlers.filter(h => h !== handler) ); } }

// Publicação de evento emit<T>(event: string, payload: T): void { const handlers = this.listeners.get(event); if (handlers) { handlers.forEach(handler => handler(payload)); } }

// Limpeza de todas as inscrições clear(): void { this.listeners.clear(); }}

export const eventBus = new EventBus();


Exemplo de uso com eventos tipados



Para aumentar a segurança de tipos, podemos definir interfaces de eventos:



// Definindo tipos de eventosinterface AppEvents {  'user:login': { userId: string; timestamp: number };  'user:logout': { userId: string };  'data:update': { id: string; data: unknown };  'notification:show': { message: string; type: 'success' | 'error' | 'info' };}

// Criando um barramento tipadoclass TypedEventBus { private listeners: Map<string, Function[]> = new Map();

on<K extends keyof AppEvents>( event: K, handler: (payload: AppEvents[K]) => void ): void { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event)!.push(handler); }

emit<K extends keyof AppEvents>( event: K, payload: AppEvents[K] ): void { const handlers = this.listeners.get(event); if (handlers) { handlers.forEach(handler => handler(payload)); } }

off<K extends keyof AppEvents>( event: K, handler: (payload: AppEvents[K]) => void ): void { const handlers = this.listeners.get(event); if (handlers) { this.listeners.set( event, handlers.filter(h => h !== handler) ); } }}

export const typedBus = new TypedEventBus();


Exemplo prático: sistema de notificações



Vamos considerar um cenário real — a criação de um sistema de notificações usando Event Bus:

Recommendations