A lightweight, type-safe event bus implementation in TypeScript that supports asynchronous event handling.
- π Type-safe event handling with TypeScript
- β‘ Asynchronous event processing
- π― Support for one-time event listeners
- π‘οΈ Error handling for event listeners
- π¦ Zero dependencies
- π§ͺ Jest testing setup included
npm install ts-async-pubsubimport { AsyncEventBus } from 'ts-async-pubsub';
// Define your event types
type EventMap = {
userCreated: { name: string; email: string };
orderPlaced: { orderId: string; amount: number };
};
// Create an instance of the event bus
const bus = new AsyncEventBus<EventMap>();// Regular subscription
bus.subscribe('userCreated', async (user) => {
console.log('New user:', user.name);
});
// One-time subscription
bus.once('userCreated', async (user) => {
console.log('Welcome,', user.name);
});// Publish an event
await bus.publish('userCreated', {
name: 'John Doe',
email: 'john@example.com'
});const handler = async (user: EventMap['userCreated']) => {
console.log('User created:', user.name);
};
bus.subscribe('userCreated', handler);
// Later...
bus.unsubscribe('userCreated', handler);// The event bus automatically handles errors in listeners
bus.subscribe('userCreated', async (user) => {
throw new Error('Something went wrong');
// Other listeners will still be called
});
// You can also handle errors in your listeners
bus.subscribe('userCreated', async (user) => {
try {
await processUser(user);
} catch (error) {
console.error('Failed to process user:', error);
}
});type EventMap = {
userCreated: { name: string; email: string };
orderPlaced: { orderId: string; amount: number };
paymentProcessed: { orderId: string; status: 'success' | 'failed' };
};
const bus = new AsyncEventBus<EventMap>();
// Subscribe to multiple events
bus.subscribe('userCreated', async (user) => {
// Handle user creation
});
bus.subscribe('orderPlaced', async (order) => {
// Handle order placement
});bus.subscribe('orderPlaced', async (order) => {
// Simulate async processing
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Order processed:', order.orderId);
});// This listener will be called only once
bus.once('userCreated', async (user) => {
console.log('First user created:', user.name);
});The main class that handles event management.
subscribe<K extends keyof TEvents>(event: K, callback: AsyncCallback<TEvents[K]>): Subscribe to an eventunsubscribe<K extends keyof TEvents>(event: K, callback: AsyncCallback<TEvents[K]>): Unsubscribe from an eventpublish<K extends keyof TEvents>(event: K, data: TEvents[K]): Promise<void>: Publish an eventonce<K extends keyof TEvents>(event: K, callback: AsyncCallback<TEvents[K]>): Subscribe to an event once
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Check test coverage
npm run test:coveragesrc/
βββ EventBus.ts # Main implementation
βββ types/ # Type definitions
βββ __tests__/ # Test files
βββ demo.ts # Usage example
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
ISC