Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion types/newman/newman-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const workingDir = "path/to/working/directory";
const insecureFileRead = true;
const requestAgent = new http.Agent();

// $ExpectType EventEmitter
// $ExpectType EventEmitter<DefaultEventMap>
run(
{
collection,
Expand Down
2 changes: 1 addition & 1 deletion types/node-red/node-red-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function REDTests() {
// $ExpectType Util
RED.util;

// $ExpectType EventEmitter
// $ExpectType EventEmitter<DefaultEventMap>
RED.events;

// $ExpectType Hooks
Expand Down
59 changes: 41 additions & 18 deletions types/node/events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,30 @@ declare module "events" {
interface StaticEventEmitterOptions {
signal?: AbortSignal | undefined;
}
interface EventEmitter extends NodeJS.EventEmitter {}
interface EventEmitter<T extends EventMap<T> = DefaultEventMap> extends NodeJS.EventEmitter<T> {}
type EventMap<T> = Record<keyof T, any[]> | DefaultEventMap;
type DefaultEventMap = [never];
const s: unique symbol;
type Key<K, T> = T extends DefaultEventMap ? string | symbol : K & (keyof (T & { [s]: never }));
type Key2<K, T> = T extends DefaultEventMap ? string | symbol : K & (keyof T);
type AnyRest = [...args: any[]];
type Args<K, T> = T extends DefaultEventMap ? AnyRest : (
K extends keyof T ? (
T[K] extends unknown[] ? T[K] : never
)
: never
);

type Listener<K, T, F> = T extends DefaultEventMap ? F : (
K extends keyof T ? (
T[K] extends unknown[] ? (...args: T[K]) => void : never
)
: never
);

type Listener1<K, T> = Listener<K, T, (...args: any[]) => void>;
type Listener2<K, T> = Listener<K, T, Function>;

/**
* The `EventEmitter` class is defined and exposed by the `node:events` module:
*
Expand All @@ -106,10 +129,10 @@ declare module "events" {
* It supports the following option:
* @since v0.1.26
*/
class EventEmitter {
class EventEmitter<T extends EventMap<T> = DefaultEventMap> {
constructor(options?: EventEmitterOptions);

[EventEmitter.captureRejectionSymbol]?(error: Error, event: string, ...args: any[]): void;
[EventEmitter.captureRejectionSymbol]?<K>(error: Error, event: Key<K, T>, ...args: Args<K, T>): void;

/**
* Creates a `Promise` that is fulfilled when the `EventEmitter` emits the given
Expand Down Expand Up @@ -536,13 +559,13 @@ declare module "events" {
}
global {
namespace NodeJS {
interface EventEmitter {
[EventEmitter.captureRejectionSymbol]?(error: Error, event: string, ...args: any[]): void;
interface EventEmitter<T extends EventMap<T> = DefaultEventMap> {
[EventEmitter.captureRejectionSymbol]?<K>(error: Error, event: Key<K, T>, ...args: Args<K, T>): void;
/**
* Alias for `emitter.on(eventName, listener)`.
* @since v0.1.26
*/
addListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
addListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Adds the `listener` function to the end of the listeners array for the
* event named `eventName`. No checks are made to see if the `listener` has
Expand Down Expand Up @@ -574,7 +597,7 @@ declare module "events" {
* @param eventName The name of the event.
* @param listener The callback function
*/
on(eventName: string | symbol, listener: (...args: any[]) => void): this;
on<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Adds a **one-time**`listener` function for the event named `eventName`. The
* next time `eventName` is triggered, this listener is removed and then invoked.
Expand Down Expand Up @@ -604,7 +627,7 @@ declare module "events" {
* @param eventName The name of the event.
* @param listener The callback function
*/
once(eventName: string | symbol, listener: (...args: any[]) => void): this;
once<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Removes the specified `listener` from the listener array for the event named`eventName`.
*
Expand Down Expand Up @@ -687,12 +710,12 @@ declare module "events" {
* Returns a reference to the `EventEmitter`, so that calls can be chained.
* @since v0.1.26
*/
removeListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
removeListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Alias for `emitter.removeListener()`.
* @since v10.0.0
*/
off(eventName: string | symbol, listener: (...args: any[]) => void): this;
off<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Removes all listeners, or those of the specified `eventName`.
*
Expand All @@ -703,7 +726,7 @@ declare module "events" {
* Returns a reference to the `EventEmitter`, so that calls can be chained.
* @since v0.1.26
*/
removeAllListeners(event?: string | symbol): this;
removeAllListeners(event?: Key<unknown, T>): this;
/**
* By default `EventEmitter`s will print a warning if more than `10` listeners are
* added for a particular event. This is a useful default that helps finding
Expand Down Expand Up @@ -732,7 +755,7 @@ declare module "events" {
* ```
* @since v0.1.26
*/
listeners(eventName: string | symbol): Function[];
listeners<K>(eventName: Key<K, T>): Array<Listener2<K, T>>;
/**
* Returns a copy of the array of listeners for the event named `eventName`,
* including any wrappers (such as those created by `.once()`).
Expand Down Expand Up @@ -763,7 +786,7 @@ declare module "events" {
* ```
* @since v9.4.0
*/
rawListeners(eventName: string | symbol): Function[];
rawListeners<K>(eventName: Key<K, T>): Array<Listener2<K, T>>;
/**
* Synchronously calls each of the listeners registered for the event named`eventName`, in the order they were registered, passing the supplied arguments
* to each.
Expand Down Expand Up @@ -804,7 +827,7 @@ declare module "events" {
* ```
* @since v0.1.26
*/
emit(eventName: string | symbol, ...args: any[]): boolean;
emit<K>(eventName: Key<K, T>, ...args: Args<K, T>): boolean;
/**
* Returns the number of listeners listening for the event named `eventName`.
* If `listener` is provided, it will return how many times the listener is found
Expand All @@ -813,7 +836,7 @@ declare module "events" {
* @param eventName The name of the event being listened for
* @param listener The event handler function
*/
listenerCount(eventName: string | symbol, listener?: Function): number;
listenerCount<K>(eventName: Key<K, T>, listener?: Listener2<K, T>): number;
/**
* Adds the `listener` function to the _beginning_ of the listeners array for the
* event named `eventName`. No checks are made to see if the `listener` has
Expand All @@ -831,7 +854,7 @@ declare module "events" {
* @param eventName The name of the event.
* @param listener The callback function
*/
prependListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
prependListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Adds a **one-time**`listener` function for the event named `eventName` to the _beginning_ of the listeners array. The next time `eventName` is triggered, this
* listener is removed, and then invoked.
Expand All @@ -847,7 +870,7 @@ declare module "events" {
* @param eventName The name of the event.
* @param listener The callback function
*/
prependOnceListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener<K>(eventName: Key<K, T>, listener: Listener1<K, T>): this;
/**
* Returns an array listing the events for which the emitter has registered
* listeners. The values in the array are strings or `Symbol`s.
Expand All @@ -867,7 +890,7 @@ declare module "events" {
* ```
* @since v6.0.0
*/
eventNames(): Array<string | symbol>;
eventNames(): Array<(string | symbol) & Key2<unknown, T>>;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions types/node/node-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "./test/diagnostics_channel";
import "./test/dns";
import "./test/dom-events"; // dom-events behaves differently under lib-dom
import "./test/events";
import "./test/events_generic";
import "./test/fs";
import "./test/globals";
import "./test/http";
Expand Down
17 changes: 17 additions & 0 deletions types/node/test/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,20 @@ async function test() {
emitter.triggerAsyncId; // $ExpectType number
emitter.emitDestroy();
}

{
class MyEmitter extends events.EventEmitter {
addListener(event: string, listener: () => void): this {
return this;
}
listeners(event: string): Array<() => void> {
return [];
}
emit(event: string, ...args: any[]): boolean {
return true;
}
listenerCount(type: string): number {
return 0;
}
}
}
Loading