An open API service indexing awesome lists of open source software.

https://github.com/alessiofrittoli/event-emitter

Cross-env TypeScript Event Emitter
https://github.com/alessiofrittoli/event-emitter

event-emitter events

Last synced: 2 months ago
JSON representation

Cross-env TypeScript Event Emitter

Awesome Lists containing this project

README

        

# Event Emitter 🔊

[![NPM Latest Version][version-badge]][npm-url] [![Coverage Status][coverage-badge]][coverage-url] [![Socket Status][socket-badge]][socket-url] [![NPM Monthly Downloads][downloads-badge]][npm-url] [![Dependencies][deps-badge]][deps-url]

[![GitHub Sponsor][sponsor-badge]][sponsor-url]

[version-badge]: https://img.shields.io/npm/v/%40alessiofrittoli%2Fevent-emitter
[npm-url]: https://npmjs.org/package/%40alessiofrittoli%2Fevent-emitter
[coverage-badge]: https://coveralls.io/repos/github/alessiofrittoli/event-emitter/badge.svg
[coverage-url]: https://coveralls.io/github/alessiofrittoli/event-emitter
[socket-badge]: https://socket.dev/api/badge/npm/package/@alessiofrittoli/event-emitter
[socket-url]: https://socket.dev/npm/package/@alessiofrittoli/event-emitter/overview
[downloads-badge]: https://img.shields.io/npm/dm/%40alessiofrittoli%2Fevent-emitter.svg
[deps-badge]: https://img.shields.io/librariesio/release/npm/%40alessiofrittoli%2Fevent-emitter
[deps-url]: https://libraries.io/npm/%40alessiofrittoli%2Fevent-emitter

[sponsor-badge]: https://img.shields.io/static/v1?label=Fund%20this%20package&message=%E2%9D%A4&logo=GitHub&color=%23DB61A2
[sponsor-url]: https://github.com/sponsors/alessiofrittoli

## Cross-env TypeScript Event Emitter

A cross-environment implementation of an `EventEmitter` that works seamlessly in **Node.js**, **Edge Runtime** (such as Next.js middleware), and **browser** environments.

The `EventEmitter` class provides a mechanism to handle events and their listeners.
It allows you to register event listeners, emit events, and manage the listeners for those events.

### Table of Contents

- [Getting started](#getting-started)
- [API Reference](#api-reference)
- [`EventEmitter` Class](#eventemitter-class)
- [Constructor](#constructor)
- [Methods](#methods)
- [Types](#types)
- [Examples](#examples)
- [Development](#development)
- [Install depenendencies](#install-depenendencies)
- [Build the source code](#build-the-source-code)
- [ESLint](#eslint)
- [Jest](#jest)
- [Contributing](#contributing)
- [Security](#security)
- [Credits](#made-with-)

---

### Getting started

Run the following command to start using `event-emitter` in your projects:

```bash
npm i @alessiofrittoli/event-emitter
```

or using `pnpm`

```bash
pnpm i @alessiofrittoli/event-emitter
```

---

### API Reference

#### `EventEmitter` Class

##### Constructor

```ts
new EventEmitter( options?: EventEmitterOptions )
```

Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `options` | `EventEmitterOptions` | - | Optional configuration object for the emitter instance. |
| `options.captureRejections` | `boolean` | `false` | If set to `true`, captures and handles promise rejections in listeners. |

---

##### Methods

###### `EventEmitter.emit()`

Emits an event to all registered listeners.

Parameters

| Parameter | Type | Description |
|-----------|--------------|----------------------------------------|
| `event` | `K` | The event name to emit. |
| `args` | `Args` | The arguments passed to the listeners. |

---

###### `EventEmitter.on()`

Adds a listener for the specified event.

Parameters

| Parameter | Type | Description |
|------------|------------------|---------------------------------------------------------|
| `event` | `K` | The event name to listen for. |
| `listener` | `Listener` | The listener function called when the event is emitted. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.addListener()`

Alias for `EventEmitter.on( event, listener )`.

---

###### `EventEmitter.prepend()`

Adds a listener to the beginning of the listener array for the specified event.

Parameters

| Parameter | Type | Description |
|------------|------------------|---------------------------------------------------------|
| `event` | `K` | The event name to listen for. |
| `listener` | `Listener` | The listener function called when the event is emitted. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.prependListener()`

Alias for `EventEmitter.prepend( event, listener )`.

---

###### `EventEmitter.once()`

Adds a one-time listener for the specified event. Even if the event is emitted multiple times, listeners registered with `.once()` method will only get called one single time.

Parameters

| Parameter | Type | Description |
|------------|------------------|---------------------------------------------------------|
| `event` | `K` | The event name to listen for. |
| `listener` | `Listener` | The listener function called when the event is emitted. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.prependOnce()`

Adds a one-time listener to the beginning of the listener array for the specified event.

Parameters

| Parameter | Type | Description |
|------------|------------------|---------------------------------------------------------|
| `event` | `K` | The event name to listen for. |
| `listener` | `Listener` | The listener function called when the event is emitted. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.prependOnceListener()`

Alias for `EventEmitter.prependOnce( event, listener )`.

---

###### `EventEmitter.off()`

Removes a listener for the specified event.

Parameters

| Parameter | Type | Description |
|------------|------------------|---------------------------------------------------------|
| `event` | `K` | The event name to remove the listener from. |
| `listener` | `Listener` | The listener function to remove from the given `event`. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.removeListener()`

Alias for `EventEmitter.off( event, listener )`.

---

###### `EventEmitter.removeAllListeners()`

Removes all listeners for a specified event or all events.

Parameters

| Parameter | Type | Description |
|------------|------------------|---------------------------------------------------------|
| `event` | `K` | (Optional) The event name to remove listeners from. |
| `listener` | `Listener` | (Optional) The listener function to remove. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.getMaxListeners()`

Gets the current maximum number of listeners. Default: `EventEmitter.defaultMaxListeners` (10).

Returns

Type `number`

The current maximum number of listeners.

---

###### `EventEmitter.setMaxListeners()`

Sets the maximum number of listeners allowed for each event.

By default, a maximum of `10` listeners can be registered for any single event. This limit can be changed for individual `EventEmitter` instances using the `EventEmitter.setMaxListeners( n )` method.

This is not a hard limit. The `EventEmitter` instance will allow more listeners to be added but will output a trace warning to stderr indicating that a "possible EventEmitter memory leak" has been detected.

Parameters

| Parameter | Type | Description |
|-----------|----------|----------------------------------|
| `n` | `number` | The maximum number of listeners. |

---

Returns

Type: `EventEmitter`

The current `EventEmitter` instance so that calls can be chained.

---

###### `EventEmitter.listenerCount()`

Gets the number of listeners for the specified event.

Parameters

| Parameter | Type | Description |
|------------|------------------|----------------------------------------------------------|
| `event` | `K` | The event name to check the listeners for. |
| `listener` | `Listener` | (Optional) The specific listener to count (if provided). |

---

Returns

Type: `number`

The number of listeners for the specified event and optionally for the given listener.

---

###### `EventEmitter.listeners()`

Returns a list of listeners for the specified event.

Parameters

| Parameter | Type | Description |
|-----------|------|--------------------------------------|
| `event` | `K` | The event name to get listeners for. |

---

Returns

Type: `( Listener )[]`

An array of registered listeners. Even if the listener is registered using the `.once()` method, the actual listener is returned instead of the `OnceListenerWrapper`.

---

###### `EventEmitter.rawListeners()`

Returns a copy of the array of listeners for the specified event, including any wrappers (such as those created by `.once()`).

Parameters

| Parameter | Type | Description |
|-----------|------|--------------------------------------|
| `event` | `K` | The event name to get listeners for. |

---

Returns

Type: `( Listener | OnceListenerWrapper )[]`

An array of registered listener callback.

If a listener has been registered using the `.once()` method a `OnceListenerWrapper` is returned. In that case the original listener can be retrieved through the `listener` property.

---

###### `EventEmitter.eventNames()`

Returns a list of all event names.

Returns

Type: `( keyof T )[]`

An array of registered event names.

---

#### Types

##### `EventEmitterOptions`

Options for configuring the `EventEmitter`.

Properties

| Proeprty | Type | Description |
|---------------------|-----------|-------------|
| `captureRejections` | `boolean` | If set to true, captures and handles promise rejections in listeners. |

---

##### `Listener`

Defines the type of a listener function.

Properties

| Proeprty | Type | Description |
|----------|--------------|-------------|
| `args` | `Args` | Arguments passed to the listener corresponding to the event key. |

---

##### `OnceListenerWrapper`

A wrapper for listeners that should be invoked only once.

Properties

| Proeprty | Type | Description |
|------------|------------------|-------------|
| `args` | `Args` | Arguments passed to the listener corresponding to the event key. |
| `listener` | `Listener` | The actual listener function to be invoked. |

---

##### `Args`

A utility type that resolves to a specific type based on the provided keys and event map.

---

#### Examples

##### Defining custom types

Details

```ts
import type { Listener } from '@alessiofrittoli/event-emitter'

// Define an event map for your EventEmitter
interface MyEvents
{
greet : [ name: string ] // The 'greet' event takes a string argument
farewell : [ name: Error ] // The 'farewell' event also takes a string argument
error : [ error: Error ] // The 'error' event takes an Error argument
}

// Optionally define listeners types
type OnGreetEventListener = Listener
type OnFarewellEventListener = Listener
type OnErrorEventListener = Listener
```

---

##### Emitting and Listening events

Declaring listeners

```ts
const greetListener: OnGreetEventListener = name => {
console.log( `Hello, ${ name }!` )
}

const farewellListener: OnFarewellEventListener = name => {
console.log( `Goodbye, ${ name }!` )
}

const errorListener: OnErrorEventListener = error => {
console.error( 'Something went wrong.', error.message )
}
```

---

Registering listeners and emitting events

```ts
import { EventEmitter } from '@alessiofrittoli/event-emitter'

const emitter = new EventEmitter()

// Attach listeners
emitter.on( 'greet', greetListener )
emitter.on( 'farewell', farewellListener )
emitter.on( 'error', errorListener )

// Emit events
emitter.emit( 'greet', 'Foo' )
emitter.emit( 'farewell', 'Bar' )
emitter.emit( 'error', new Error( 'An error occured.' ) )
```

---

##### One-time events listeners

Details

```ts
const emitter = new EventEmitter()

// Define a listener for the 'greet' event that should only be called once
const greetOnceListener: OnGreetEventListener = name => {
console.log( `Once Hello, ${ name }!` )
}

emitter.once( 'greet', greetOnceListener )

// Emit the event
emitter.emit( 'greet', 'Foo' )
// `greetOnceListener` won't be called anymore, as the listener was removed after the first call.
emitter.emit( 'greet', 'Bob' )
```

---

##### Error Handling with `captureRejections`

Details

```ts
const emitter = new EventEmitter( { captureRejections: true } )

const greetListener: OnGreetEventListener = name => {
if ( name === 'He-Who-Must-Not-Be-Named' ) {
throw new Error( 'nooose!' )
}
console.log( `Howdy, ${ name }!` )
}

const errorListener: OnErrorEventListener = error => {
console.error( 'Caught your', error.message )
}

// Add listeners
emitter.on( 'greet', greetListener )
emitter.on( 'error', errorListener )

// Emit events
emitter.emit( 'greet', 'Foo' )
emitter.emit( 'greet', 'He-Who-Must-Not-Be-Named' )
```

---

##### Managing Max Listeners

Details

```ts
const emitter = (
new EventEmitter()
.setMaxListeners( 1 )
)

const greetListener1: OnGreetEventListener = name => {
console.log( `Hello, ${ name }!` )
}

const greetListener2: OnGreetEventListener = name => {
console.log( `Hi, ${ name }!` )
}

const greetListener3: OnGreetEventListener = name => {
console.log( `Howdy, ${ name }!` )
}

// Attach listeners
emitter.on( 'greet', greetListener1 )
emitter.on( 'greet', greetListener2 ) // This will trigger a warning but it will get executed anyway.
emitter.on( 'greet', greetListener3 ) // This won't trigger a warning. Warnings are emitted once.

emitter.emit( 'greet', 'Foo' )
// Output:
// Hello, Foo!
// Hi, Foo!
// Howdy, Foo!
```

---

##### Using `prepend` and `prependOnce`

Details

```ts
const emitter = new EventEmitter()

// Attach listeners
emitter.on( 'greet', name => {
console.log( `A: Hello! Better late than never ${ name }.` )
} )
emitter.prepend( 'greet', name => {
console.log( `B: Hello, ${ name }!` )
} )
emitter.prependOnce( 'greet', name => {
console.log( `C: Once Hello, ${ name }! I won't say hello to you, Bar.` )
} )

// Emit events
emitter.emit( 'greet', 'Foo' )
emitter.emit( 'greet', 'Bar' )
// Outputs:
// C: Once Hello, Foo! I won't say hello to you, Bar.
// B: Hello, Foo!
// A: Hello! Better late than never Foo.
// B: Hello, Bar!
// A: Hello! Better late than never Bar.
```

---

##### Retrieve listeners count

Get listeners count for a specific event

```ts
const emitter = (
new EventEmitter()
.on( 'greet', () => {} )
.on( 'greet', () => {} )
.on( 'farewell', () => {} )
)

console.log( emitter.listenerCount( 'greet' ) ) // Outputs: `2`
console.log( emitter.listenerCount( 'farewell' ) ) // Outputs: `1`
console.log( emitter.listenerCount( 'error' ) ) // Outputs: `0`
```

---

Get listeners count for a specific event and listener

```ts
const callback1 = () => {}
const callback2 = () => {}

const emitter = (
new EventEmitter()
.on( 'greet', callback1 )
.on( 'greet', callback1 )
.on( 'greet', callback2 )
)

console.log( emitter.listenerCount( 'greet', callback1 ) ) // Outputs: `2`
console.log( emitter.listenerCount( 'greet', callback2 ) ) // Outputs: `1`
```

---

##### Retrieve registered listeners

Get registerd listeners array

We register `callback2` with `EventEmitter.once()` to verify that we correctly get the original `callback2` instead of the `onceWrapper` function in the returning array.

```ts
const callback1 = () => {}
const callback2 = () => {}

const emitter = (
new EventEmitter()
.on( 'greet', callback1 )
.once( 'greet', callback2 )
.on( 'farewell', callback1 )
)
const functions = emitter.listeners( 'greet' ) // Listener[]

console.log( functions )
// Outputs: `[ [Function: callback1], [Function: callback2] ]`

functions.map( listener => {
listener() // manually execute the listener.
} )
```

---

Get registerd raw listeners array

Again we register `callback2` with `EventEmitter.once()` to verify that we correctly get the `onceWrapper` function instead of the original `callback2` listener in the returning array.

```ts
const callback1 = () => {}
const callback2 = () => {}

const emitter = (
new EventEmitter()
.on( 'greet', callback1 )
.once( 'greet', callback2 )
.on( 'farewell', callback1 )
)

const functions = emitter.rawListeners( 'greet' ) // ( Listener | OnceListenerWrapper )[]

console.log( functions )
// Outputs: `[ [Function: callback1], [Function: onceWrapper] { listener: [Function: callback2] } ]`

functions.map( callback => {
/** Manually execute the listener. If this is a `onceWrapper` function, it will remove the listener from the listeners array and then execute the original listener function. */
callback()

/** Or execute the original listener without removing it from the listeners array. */
if ( 'listener' in callback ) {
callback.listener()
}
} )
```

---

##### Batch removing listeners

Remove all attached listeners to every registered event

```ts
const emitter = (
new EventEmitter()
.on( 'greet', () => {} )
.once( 'greet', () => {} )
.on( 'farewell', () => {} )
)

console.log( emitter.listenerCount( 'greet' ) ) // Outputs: `2`
console.log( emitter.listenerCount( 'farewell' ) ) // Outputs: `1`
console.log( emitter.listenerCount( 'error' ) ) // Outputs: `0`

emitter.removeAllListeners()

console.log( emitter.listenerCount( 'greet' ) ) // Outputs: `0`
console.log( emitter.listenerCount( 'farewell' ) ) // Outputs: `0`
console.log( emitter.listenerCount( 'error' ) ) // Outputs: `0`
```

---

Remove all attached listeners to a specific event

```ts
const emitter = (
new EventEmitter()
.on( 'greet', () => {} )
.once( 'greet', () => {} )
.on( 'farewell', () => {} )
.removeAllListeners( 'greet' )
)

console.log( emitter.listenerCount( 'greet' ) ) // Outputs: `0`
console.log( emitter.listenerCount( 'farewell' ) ) // Outputs: `1`
console.log( emitter.listenerCount( 'error' ) ) // Outputs: `0`
```

---

Remove specifc listeners attached to a specific event

```ts
const callback1 = () => {}
const callback2 = () => {}

const emitter = (
new EventEmitter()
.on( 'greet', callback1 )
.once( 'greet', callback1 )
.once( 'greet', callback2 )
.on( 'farewell', callback1 )
.removeAllListeners( 'greet', callback1 )
)

console.log( emitter.listenerCount( 'greet' ) ) // Outputs: `1`
console.log( emitter.listenerCount( 'farewell' ) ) // Outputs: `1`
console.log( emitter.listenerCount( 'error' ) ) // Outputs: `0`
```

---

### Development

#### Install depenendencies

```bash
npm install
```

or using `pnpm`

```bash
pnpm i
```

#### Build the source code

Run the following command to test and build code for distribution.

```bash
pnpm build
```

#### [ESLint](https://www.npmjs.com/package/eslint)

warnings / errors check.

```bash
pnpm lint
```

#### [Jest](https://npmjs.com/package/jest)

Run all the defined test suites by running the following:

```bash
# Run tests and watch file changes.
pnpm test:watch

# Run tests in a CI environment.
pnpm test:ci
```

- See [`package.json`](./package.json) file scripts for more info.

Run tests with coverage.

An HTTP server is then started to serve coverage files from `./coverage` folder.

⚠️ You may see a blank page the first time you run this command. Simply refresh the browser to see the updates.

```bash
test:coverage:serve
```

---

### Contributing

Contributions are truly welcome!

Please refer to the [Contributing Doc](./CONTRIBUTING.md) for more information on how to start contributing to this project.

Help keep this project up to date with [GitHub Sponsor][sponsor-url].

[![GitHub Sponsor][sponsor-badge]][sponsor-url]

---

### Security

If you believe you have found a security vulnerability, we encourage you to **_responsibly disclose this and NOT open a public issue_**. We will investigate all legitimate reports. Email `[email protected]` to disclose any security vulnerabilities.

### Made with ☕




avatar






Alessio Frittoli





https://alessiofrittoli.it |
[email protected]