Skip to content

Commit

Permalink
feat(Client): add wrapper methods for EventEmitter.{on,once}
Browse files Browse the repository at this point in the history
Remove broken Node.js EventEmitter overloads
  • Loading branch information
Renegade334 committed Oct 24, 2024
1 parent 48a9c66 commit bc11ef8
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 15 deletions.
20 changes: 20 additions & 0 deletions packages/discord.js/src/client/BaseClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,26 @@ class BaseClient extends EventEmitter {
}
}

/**
* Shorthand for `EventEmitter.on(client, ...)`
* @param {string} eventName The name of the client event to listen for
* @param {Object} [options] Passed as the `options` argument to `EventEmitter.on()`
* @returns {AsyncIterator} An async iterator that yields on each emitted event
*/
eventIterator(eventName, options = {}) {
return this.constructor.on(this, eventName, options);
}

/**
* Shorthand for `EventEmitter.once(client, ...)`
* @param {string} eventName The name of the client event to listen for
* @param {Object} [options] Passed as the `options` argument to `EventEmitter.once()`
* @returns {Promise<Array<*>>} A promise that resolves to the next emitted event
*/
awaitEvent(eventName, options = {}) {
return this.constructor.once(this, eventName, options);
}

toJSON(...props) {
return flatten(this, ...props);
}
Expand Down
26 changes: 14 additions & 12 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ import {
GatewayDispatchPayload,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
import { Abortable, EventEmitter } from 'node:events';
import { Stream } from 'node:stream';
import { MessagePort, Worker } from 'node:worker_threads';
import {
Expand Down Expand Up @@ -512,6 +512,8 @@ export class BaseClient extends EventEmitter implements AsyncDisposable {
public options: ClientOptions | WebhookClientOptions;
public rest: REST;
public destroy(): void;
public eventIterator(eventName: string | symbol, options?: Abortable): AsyncIterableIterator<any[]>;
public awaitEvent(eventName: string | symbol, options?: Abortable): Promise<any[]>;
public toJSON(...props: Record<string, boolean | string>[]): unknown;
public [Symbol.asyncDispose](): Promise<void>;
}
Expand Down Expand Up @@ -967,17 +969,17 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
// This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.
private readonly _ready: Ready;

// Override inherited static EventEmitter methods, with added type checks for Client events.
public static once<Emitter extends EventEmitter, Event extends keyof ClientEvents>(
eventEmitter: Emitter,
eventName: Emitter extends Client ? Event : string | symbol,
options?: { signal?: AbortSignal | undefined },
): Promise<Emitter extends Client ? ClientEvents[Event] : any[]>;
public static on<Emitter extends EventEmitter, Event extends keyof ClientEvents>(
eventEmitter: Emitter,
eventName: Emitter extends Client ? Event : string | symbol,
options?: { signal?: AbortSignal | undefined },
): AsyncIterableIterator<Emitter extends Client ? ClientEvents[Event] : any[]>;
// Overloads for BaseClient's EventEmitter static method wrappers, with ClientEvents-aware typings.
public eventIterator<Event extends keyof ClientEvents>(
eventName: Event,
options?: Abortable,
): AsyncIterableIterator<ClientEvents[Event]>;
public eventIterator(eventName: string | symbol, options?: Abortable): AsyncIterableIterator<any[]>;
public awaitEvent<Event extends keyof ClientEvents>(
eventName: Event,
options?: Abortable,
): Promise<ClientEvents[Event]>;
public awaitEvent(eventName: string | symbol, options?: Abortable): Promise<any[]>;

public application: If<Ready, ClientApplication>;
public channels: ChannelManager;
Expand Down
8 changes: 5 additions & 3 deletions packages/discord.js/typings/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1301,9 +1301,11 @@ client.on('guildCreate', async g => {
);
});

// EventEmitter static method overrides
expectType<Promise<[Client<true>]>>(Client.once(client, 'clientReady'));
expectType<AsyncIterableIterator<[Client<true>]>>(Client.on(client, 'clientReady'));
// EventEmitter static method wrappers
expectType<Promise<[Client<true>]>>(client.awaitEvent('clientReady'));
expectType<Promise<any[]>>(client.awaitEvent('unknownEvent'));
expectType<AsyncIterableIterator<[Client<true>]>>(client.eventIterator('clientReady'));
expectType<AsyncIterableIterator<any[]>>(client.eventIterator('unknownEvent'));

client.login('absolutely-valid-token');

Expand Down

0 comments on commit bc11ef8

Please sign in to comment.