@universal-packages/event-emitter
v2.2.1
Published
Event emitter 2 universal convention
Readme
Event Emitter
Rich emitted event event emitter with typescript support.
Getting Started
npm install @universal-packages/event-emitterUsage
EventEmitter class
Just instantiate the class and start emitting events.
import { EventEmitter } from '@universal-packages/event-emitter'
const emitter = new EventEmitter()
emitter.on('event', (event) => {
console.log(event)
})
emitter.emit('event', { payload: { foo: 'bar' } })
emitter.emit('error', { error: new Error('Something went wrong') })Constructor constructor
new EventEmitter(options?: EventEmitterOptions)Creates a new EventEmitter instance.
Options
delimiterStringdefault: ':'The delimiter to use for event names.maxListenersNumberdefault: 20The maximum number of listeners for an event before start considering it a memory leak.useWildcardsBooleandefault: trueWhether to use wildcards for event names. ex:'user:*or even*for all events.newListenerEventBooleandefault: trueWhether to emit a new listener event when a listener is added.removeListenerEventBooleandefault: falseWhether to emit a remove listener event when a listener is removed.verboseMemoryLeakBooleandefault: trueWhether to log memory leaks (when a listener is added after the maxListeners limit is reached).ignoreErrorsBooleandefault: trueIf false when emitting an error and no error listener is added the error will be thrown.
Getters/Setters
maxListeners
emitter.maxListenersReturns the maximum number of listeners for an event before start considering it a memory leak.
eventNames
emitter.eventNamesReturns the event names that the emitter is listening to.
listenerCount
emitter.listenerCountReturns the number of listeners for a given event.
listeners
emitter.listenersReturns the listeners for a given event.
Instance Methods
emit
emitter.emit(eventName: string | string[], event?: EventIn): booleanEmits an event for the given event name or names. Or even wildcards.
// All event listeners that start with user like user:created, user:updated, user:deleted
emitter.emit('user:*', { payload: { foo: 'bar' } })
// All event listeners will receive the event
emitter.emit('*', { payload: { foo: 'bar' } })
// Specific event, just the user:created listeners will receive the event
emitter.emit('user:created', { payload: { foo: 'bar' } })EventIn
The event object that is passed to the listener. It is packed with common and useful properties.
errorErroroptionalThis can be set with theerrorevent but you can also set errors for any reason you want.emitter.emit('task:done', { error: new Error('Something went wrong'), message: 'Task partially done, but with error' })measurementMeasurementoptionalYou may want processes to be measured. And share that when emitting an event.import { TimeMeasurer } from '@universal-packages/time-measurer' const measurer = TimeMeasurer.start() emitter.emit('task:done', { measurement: measurer.finish(), message: 'Task done' })messageStringoptionalA concise message to share with the listeners.payloadToptionalWhen the EventEmitter is event typed (a predefine number of event names and its payloads are defined) you set this to that predefine shape, other wise you can set any payload you want.emitter.emit('task:done', { payload: { foo: 'bar' } }) emitter.emit('task:done', { payload: 66 })
emitAsync
emitter.emitAsync(eventName: string | string[], event?: EventIn): Promise<any[]>Emits an event asynchronously returning a promise that resolves when all listeners are done.
addListener
emitter.addListener(eventName: string | string[], listener: ListenerFn): thisAdds a listener for a given event or events.
// Will be called when the event "event" is emitted
emitter.addListener('event', (event) => {
console.log(event)
})
// Will be called when one level event is emitted
emitter.addListener('*', (event) => {
console.log(event)
})
// Will be called when two levels event is emitted
emitter.addListener('*:*', (event) => {
console.log(event)
})
// Will be called for all events
emitter.addListener('**', (event) => {
console.log(event)
})
// Will be called when any 2event that starts with "user:" is emitted
emitter.addListener('user:*', (event) => {
console.log(event)
})
// Will be called when any event that starts with "user:" is emitted
emitter.addListener('user:**', (event) => {
console.log(event)
})
// Will be called when the event "users:created" or "users:updated" are emitted
emitter.addListener(['users:created', 'users:updated'], (event) => {
console.log(event)
})
// Will be called when the event any of the 2 level events that start with "users:" or "tasks:" are emitted
emitter.addListener(['users:*', 'tasks:*'], (event) => {
console.log(event)
})ListenerFn
(event?: EmittedEvent<TPayload>): void | Promise<void>The listener function that is called when an event is emitted. It receives all that was emitted in the #EventIn, for types events, the payload will be the shape it was types for the event.
on
emitter.on(eventName: string | string[], listener: ListenerFn): thisAdds a listener for a given event just like addListener,
emitter.on('event', (event) => {
console.log(event)
})prependListener
emitter.on(eventName: string | string[], listener: ListenerFn): thisAdds a listener for a given event just like addListener, but the listener will be called before the other listeners.
emitter.prependListener('event', (event) => {
console.log(event)
})once
emitter.once(eventName: string | string[], listener: ListenerFn): thisAdds a listener for a given event just like addListener, but the listener will be called only once.
emitter.once('event', (event) => {
console.log(event)
})prependOnceListener
emitter.prependOnceListener(eventName: string | string[], listener: ListenerFn): thisAdds a listener for a given event just like once, but the listener will be called before the other listeners.
emitter.prependOnceListener('event', (event) => {
console.log(event)
})removeListener
emitter.removeListener(eventName: string | string[], listener: ListenerFn): thisRemoves a listener for a given event or events.
// Will remove the listeners for the event "event" only
emitter.removeListener('event', (event) => {
console.log(event)
})
// Will remove the listeners for the events "users:created" and "users:updated"
emitter.removeListener(['users:created', 'users:updated'], (event) => {
console.log(event)
})off
emitter.off(eventName: string | string[], listener: ListenerFn): thisRemoves a listener for a given event or events.
removeAllListeners
emitter.removeAllListeners(eventName?: string | string[]): thisRemoves all listeners for a given event or events.
// Will remove all listeners for the event "event"
emitter.removeAllListeners('event')waitFor
emitter.waitFor(eventName: string): CancelablePromise<EmittedEvent<TPayload>[]>Waits for a given event to be emitted, it returns a cancelable promise that resolves with the emitted event.
const promise = emitter.waitFor('event')
promise.then((event) => {
console.log(event)
})hasListeners
emitter.hasListeners(eventName: string | string[]): BooleanReturns true if there are listeners for a given event or events.
// Will return true if there are listeners for the event "event"
emitter.hasListeners('event')Type-Safe Events
This library provides full TypeScript support with generic event types. You can define your event names and their payload types for complete type safety:
import { EventEmitter } from '@universal-packages/event-emitter'
// Define your event map
interface MyEvents {
'user:created': { id: string; name: string }
'user:updated': { id: string; changes: Record<string, any> }
numbers: number[]
message: string
}
// Create a typed event emitter
const emitter = new EventEmitter<MyEvents>()
// TypeScript provides autocompletion for event names
emitter.on('user:created', (event) => {
// event.payload is typed as { id: string; name: string }
console.log(`User created: ${event.payload.id}, ${event.payload.name}`)
})
// Emit with type checking
emitter.emit('user:created', {
payload: {
id: '123',
name: 'John'
}
})
// TypeScript will catch type errors:
// emitter.emit('user:created', { payload: { id: 123 } }) // Error: Type 'number' is not assignable to type 'string'
// emitter.emit('user:created', { payload: {}) // Error: Type '{}' is not assignable to type '{ id: string; name: string; }'Mixed Typed and Dynamic Events
You can use both typed and dynamic events in the same emitter:
// Use your typed events with autocompletion
emitter.on('user:created', (event) => {
// Fully typed payload
const id: string = event.payload.id
})
// Use dynamic events when needed
emitter.on('custom:event', (event: EmittedEvent<{ custom: boolean }>) => {
// Dynamic payload
console.log(event.payload)
})
// Use wildcards
emitter.onAny((eventName, event) => {
console.log(`Event fired: ${eventName}`)
})Typescript
This library is developed in TypeScript and shipped fully typed.
Contributing
The development of this library happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving this library.
License
