Héctor Valls: Software Development Blog

Cover Image for Type-safe message bus in TypeScript

Type-safe message bus in TypeScript

Building decoupled applications often requires a reliable way to handle messages between components. I have implemented a minimal, type-safe message bus that leverages TypeScript's type system: https://github.com/hvalls/typed-bus.

Usage

// 1. Define your message interfaces
interface AppMessages extends MessageRegistry {
  'user.create': {
    in: { name: string; email: string };
    out: { id: string; name: string; email: string };
  };
  'email.send': {
    in: { message: string; to: string; };
    out: { sent: boolean };
  };
}

// 2. Define your message handlers
const bus = createBus<AppMessages>()
  .handle('user.create', async ({ name, email }) => {
    const id = createUser(name, email):
    return { id, name, email };
  })
  .handle('email.send', async ({ message, to }) => {
    const sent = sendEmail(message, to);
    return { sent: true };
  });

// 3. Type-safe execution
const user = await bus.execute('user.create', {
  name: 'John',
  email: 'john@example.com'
});

Benefits

  • Type safety: Full compile-time checking for message names and payloads
  • Decoupling: Components communicate through contracts, not direct dependencies
  • Simplicity: Minimal API with fluent registration

This pattern is particularly useful for implementing CQRS, event-driven architectures, or any scenario where you need type-safe message passing between application layers.