Event Bus e o 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 o padrão Observer em TypeScript



O padrão Observer (Observador) e sua implementação prática — Event Bus (Barramento de Eventos) — são ferramentas fundamentais para construir aplicações fracamente acopladas e escaláveis. Neste artigo, analisaremos detalhadamente como implementar um Event Bus em TypeScript, usando tipagem estrita, e veremos sua aplicação em projetos educacionais.



O que é o padrão Observer?

O padrão Observer define uma relação "um para muitos" entre objetos. Quando um objeto (publicador, subject) altera seu estado, todos os objetos dependentes dele (observadores, observers) são automaticamente notificados e atualizados. Isso evita o acoplamento rígido entre componentes.



O que é um Event Bus?

Event Bus (barramento de eventos) é um mecanismo centralizado que implementa o padrão Observer. Em vez de inscrever observadores diretamente no publicador, todos os componentes se comunicam através de um barramento único. Um componente pode:

  • Inscrever-se (subscribe/listen) em um evento específico.
  • Publicar (emit/publish) um evento, que será transmitido a todos os inscritos.
  • Cancelar inscrição (unsubscribe) de um evento quando não for mais necessário.

Essa abordagem é ideal para:

  • Interação entre módulos que não precisam conhecer uns aos outros.
  • Tratamento de ações do usuário (cliques, entrada de dados).
  • Reação a mudanças de estado da aplicação (carregamento de dados, erros).


Implementação de um Event Bus em TypeScript

TypeScript adiciona um poderoso sistema de tipos, tornando o Event Bus seguro e previsível. Criaremos um barramento tipado, onde cada evento tem um conjunto estritamente definido de argumentos.



1. Definição dos tipos de eventos

Primeiro, definimos uma interface para mapear nomes de eventos e seus argumentos:

// Definimos um mapa de eventos: chave — nome do evento, valor — tipo dos argumentosinterface EventMap {    'user:login': { userId: string; timestamp: number };    'data:loaded': { items: string[] };    'error:occurred': { message: string; code: number };    // Podemos adicionar quaisquer outros eventos}


2. Criação da classe EventBus

Agora criamos a classe em si, usando genéricos para tipagem estrita:

type Listener<T> = (payload: T) => void;

class EventBus<T extends Record<string, unknown>> { private listeners: Map<keyof T, Set<Listener<unknown>>> = new Map();

// Inscrição em um evento subscribe<K extends keyof T>(event: K, listener: Listener<T[K]>): () => void { if (!this.listeners.has(event)) { this.listeners.set(event, new Set()); } const currentListeners = this.listeners.get(event)!; currentListeners.add(listener as Listener<unknown>);

// Retorna uma função para cancelar a inscrição return () => { currentListeners.delete(listener as Listener<unknown>); }; }

// Publicação de um evento emit<K extends keyof T>(event: K, payload: T[K]): void { const currentListeners = this.listeners.get(event); if (currentListeners) { currentListeners.forEach((listener) => { listener(payload); }); } }

// Cancelar inscrição de todos os eventos (útil para limpeza) clear(): void { this.listeners.clear(); }}

// Criamos uma instância do barramento com nosso mapa de eventosexport const appEventBus = new EventBus<EventMap>();


3. Exemplo de uso

Vejamos como diferentes módulos podem interagir através do Event Bus:



// Módulo de autenticaçãoclass AuthService {    login(userId: string) {        // ... lógica de login ...        appEventBus.emit('use                    

Recommendations