Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ClientEvents, CollectorFilter and Message types generic. #5447

Closed
wants to merge 5 commits into from
Closed
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
150 changes: 95 additions & 55 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ declare module 'discord.js' {
public toString(): string;
}

export class Client extends BaseClient {
constructor(options: ClientOptions);
export class Client<Partials extends PartialTypes = PartialTypes> extends BaseClient {
constructor(options: ClientOptions<Partials>);
private actions: object;
private _eval(script: string): any;
private _validateOptions(options: ClientOptions): void;
Expand Down Expand Up @@ -233,29 +233,38 @@ declare module 'discord.js' {
public sweepMessages(lifetime?: number): number;
public toJSON(): object;

public on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
public on<K extends keyof ClientEvents<Partials>>(
event: K,
listener: (...args: ClientEvents<Partials>[K]) => void,
): this;
public on<S extends string | symbol>(
event: Exclude<S, keyof ClientEvents>,
event: Exclude<S, keyof ClientEvents<Partials>>,
listener: (...args: any[]) => void,
): this;

public once<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
public once<K extends keyof ClientEvents<Partials>>(
event: K,
listener: (...args: ClientEvents<Partials>[K]) => void,
): this;
public once<S extends string | symbol>(
event: Exclude<S, keyof ClientEvents>,
event: Exclude<S, keyof ClientEvents<Partials>>,
listener: (...args: any[]) => void,
): this;

public emit<K extends keyof ClientEvents>(event: K, ...args: ClientEvents[K]): boolean;
public emit<S extends string | symbol>(event: Exclude<S, keyof ClientEvents>, ...args: any[]): boolean;
public emit<K extends keyof ClientEvents<Partials>>(event: K, ...args: ClientEvents<Partials>[K]): boolean;
public emit<S extends string | symbol>(event: Exclude<S, keyof ClientEvents<Partials>>, ...args: any[]): boolean;

public off<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
public off<K extends keyof ClientEvents<Partials>>(
event: K,
listener: (...args: ClientEvents<Partials>[K]) => void,
): this;
public off<S extends string | symbol>(
event: Exclude<S, keyof ClientEvents>,
event: Exclude<S, keyof ClientEvents<Partials>>,
listener: (...args: any[]) => void,
): this;

public removeAllListeners<K extends keyof ClientEvents>(event?: K): this;
public removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof ClientEvents>): this;
public removeAllListeners<K extends keyof ClientEvents<Partials>>(event?: K): this;
public removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof ClientEvents<Partials>>): this;
}

export class ClientApplication extends Application {
Expand Down Expand Up @@ -958,15 +967,19 @@ declare module 'discord.js' {
public toString(): string;
}

export class Message extends Base {
constructor(client: Client, data: object, channel: TextChannel | DMChannel | NewsChannel);
export class Message<SentInGuild extends boolean = boolean> extends Base {
constructor(
client: Client,
data: object,
channel: SentInGuild extends true ? TextChannel | NewsChannel : DMChannel,
);
private patch(data: object): Message;

public activity: MessageActivity | null;
public application: ClientApplication | null;
public attachments: Collection<Snowflake, MessageAttachment>;
public author: User;
public channel: TextChannel | DMChannel | NewsChannel;
public channel: SentInGuild extends true ? TextChannel | NewsChannel : DMChannel;
public readonly cleanContent: string;
public content: string;
public readonly createdAt: Date;
Expand All @@ -977,9 +990,9 @@ declare module 'discord.js' {
public readonly editedAt: Date | null;
public editedTimestamp: number | null;
public embeds: MessageEmbed[];
public readonly guild: Guild | null;
public readonly guild: SentInGuild extends true ? Guild : null;
public id: Snowflake;
public readonly member: GuildMember | null;
public readonly member: SentInGuild extends true ? GuildMember : null;
public mentions: MessageMentions;
public nonce: string | number | null;
public readonly partial: false;
Expand All @@ -993,41 +1006,47 @@ declare module 'discord.js' {
public webhookID: Snowflake | null;
public flags: Readonly<MessageFlags>;
public reference: MessageReference | null;
public readonly referencedMessage: Message | null;
public readonly referencedMessage: Message<SentInGuild> | null;
public awaitReactions(
filter: CollectorFilter,
filter: CollectorFilter<[...ClientEvents['messageReactionAdd'], Collector<Snowflake, MessageReaction>]>,
options?: AwaitReactionsOptions,
): Promise<Collection<Snowflake, MessageReaction>>;
public createReactionCollector(filter: CollectorFilter, options?: ReactionCollectorOptions): ReactionCollector;
public delete(): Promise<Message>;
public createReactionCollector(
filter: CollectorFilter<[...ClientEvents['messageReactionAdd'], Collection<Snowflake, MessageReaction>]>,
options?: ReactionCollectorOptions,
): ReactionCollector;
public delete(): Promise<Message<SentInGuild>>;
public edit(
content: APIMessageContentResolvable | MessageEditOptions | MessageEmbed | APIMessage,
): Promise<Message>;
public edit(content: StringResolvable, options: MessageEditOptions | MessageEmbed): Promise<Message>;
): Promise<Message<SentInGuild>>;
public edit(content: StringResolvable, options: MessageEditOptions | MessageEmbed): Promise<Message<SentInGuild>>;
public equals(message: Message, rawData: object): boolean;
public fetchWebhook(): Promise<Webhook>;
public crosspost(): Promise<Message>;
public fetch(force?: boolean): Promise<Message>;
public pin(options?: { reason?: string }): Promise<Message>;
public crosspost(): Promise<Message<SentInGuild>>;
public fetch(force?: boolean): Promise<Message<SentInGuild>>;
public pin(options?: { reason?: string }): Promise<Message<SentInGuild>>;
public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>;
public reply(
content: APIMessageContentResolvable | (MessageOptions & { split?: false }) | MessageAdditions,
): Promise<Message>;
public reply(options: MessageOptions & { split: true | SplitOptions }): Promise<Message[]>;
public reply(options: MessageOptions | APIMessage): Promise<Message | Message[]>;
): Promise<Message<SentInGuild>>;
public reply(options: MessageOptions & { split: true | SplitOptions }): Promise<Message<SentInGuild>[]>;
public reply(options: MessageOptions | APIMessage): Promise<Message<SentInGuild> | Message<SentInGuild>[]>;
public reply(
content: StringResolvable,
options: (MessageOptions & { split?: false }) | MessageAdditions,
): Promise<Message>;
): Promise<Message<SentInGuild>>;
public reply(
content: StringResolvable,
options: MessageOptions & { split: true | SplitOptions },
): Promise<Message[]>;
public reply(content: StringResolvable, options: MessageOptions): Promise<Message | Message[]>;
public suppressEmbeds(suppress?: boolean): Promise<Message>;
): Promise<Message<SentInGuild>[]>;
public reply(
content: StringResolvable,
options: MessageOptions,
): Promise<Message<SentInGuild> | Message<SentInGuild>[]>;
public suppressEmbeds(suppress?: boolean): Promise<Message<SentInGuild>>;
public toJSON(): object;
public toString(): string;
public unpin(options?: { reason?: string }): Promise<Message>;
public unpin(options?: { reason?: string }): Promise<Message<SentInGuild>>;
}

export class MessageAttachment {
Expand All @@ -1048,7 +1067,11 @@ declare module 'discord.js' {
}

export class MessageCollector extends Collector<Snowflake, Message> {
constructor(channel: TextChannel | DMChannel, filter: CollectorFilter, options?: MessageCollectorOptions);
constructor(
channel: TextChannel | DMChannel,
filter: CollectorFilter<[...ClientEvents['message'], Collector<Snowflake, Message>]>,
options?: MessageCollectorOptions,
);
private _handleChannelDeletion(channel: GuildChannel): void;
private _handleGuildDeletion(guild: Guild): void;

Expand Down Expand Up @@ -1225,7 +1248,11 @@ declare module 'discord.js' {
}

export class ReactionCollector extends Collector<Snowflake, MessageReaction> {
constructor(message: Message, filter: CollectorFilter, options?: ReactionCollectorOptions);
constructor(
message: Message,
filter: CollectorFilter<[...ClientEvents['messageReactionAdd'], Collector<Snowflake, MessageReaction>]>,
options?: ReactionCollectorOptions,
);
private _handleChannelDeletion(channel: GuildChannel): void;
private _handleGuildDeletion(guild: Guild): void;
private _handleMessageDeletion(message: Message): void;
Expand Down Expand Up @@ -2102,12 +2129,18 @@ declare module 'discord.js' {
readonly lastPinAt: Date | null;
typing: boolean;
typingCount: number;
awaitMessages(filter: CollectorFilter, options?: AwaitMessagesOptions): Promise<Collection<Snowflake, Message>>;
awaitMessages(
filter: CollectorFilter<[...ClientEvents['message'], Collector<Snowflake, Message>]>,
options?: AwaitMessagesOptions,
): Promise<Collection<Snowflake, Message>>;
bulkDelete(
messages: Collection<Snowflake, Message> | readonly MessageResolvable[] | number,
filterOld?: boolean,
): Promise<Collection<Snowflake, Message>>;
createMessageCollector(filter: CollectorFilter, options?: MessageCollectorOptions): MessageCollector;
createMessageCollector(
filter: CollectorFilter<[...ClientEvents['message'], Collector<Snowflake, Message>]>,
options?: MessageCollectorOptions,
): MessageCollector;
startTyping(count?: number): Promise<void>;
stopTyping(force?: boolean): void;
}
Expand Down Expand Up @@ -2420,10 +2453,10 @@ declare module 'discord.js' {

type ChannelResolvable = Channel | Snowflake;

interface ClientEvents {
interface ClientEvents<Partials extends PartialTypes = PartialTypes> {
channelCreate: [channel: GuildChannel];
channelDelete: [channel: DMChannel | GuildChannel];
channelPinsUpdate: [channel: Channel | PartialDMChannel, date: Date];
channelPinsUpdate: [channel: PartialDataType<Partials>['channel'], date: Date];
channelUpdate: [oldChannel: Channel, newChannel: Channel];
debug: [message: string];
warn: [message: string];
Expand All @@ -2438,26 +2471,26 @@ declare module 'discord.js' {
guildUnavailable: [guild: Guild];
guildIntegrationsUpdate: [guild: Guild];
guildMemberAdd: [member: GuildMember];
guildMemberAvailable: [member: GuildMember | PartialGuildMember];
guildMemberRemove: [member: GuildMember | PartialGuildMember];
guildMemberAvailable: [member: PartialDataType<Partials>['guildMember']];
guildMemberRemove: [member: PartialDataType<Partials>['guildMember']];
guildMembersChunk: [
members: Collection<Snowflake, GuildMember>,
guild: Guild,
data: { count: number; index: number; nonce: string | undefined },
];
guildMemberSpeaking: [member: GuildMember | PartialGuildMember, speaking: Readonly<Speaking>];
guildMemberUpdate: [oldMember: GuildMember | PartialGuildMember, newMember: GuildMember];
guildMemberSpeaking: [member: PartialDataType<Partials>['guildMember'], speaking: Readonly<Speaking>];
guildMemberUpdate: [oldMember: PartialDataType<Partials>['guildMember'], newMember: GuildMember];
guildUpdate: [oldGuild: Guild, newGuild: Guild];
inviteCreate: [invite: Invite];
inviteDelete: [invite: Invite];
message: [message: Message];
messageDelete: [message: Message | PartialMessage];
messageReactionRemoveAll: [message: Message | PartialMessage];
messageDelete: [message: PartialDataType<Partials>['message']];
messageReactionRemoveAll: [message: PartialDataType<Partials>['message']];
messageReactionRemoveEmoji: [reaction: MessageReaction];
messageDeleteBulk: [messages: Collection<Snowflake, Message | PartialMessage>];
messageReactionAdd: [message: MessageReaction, user: User | PartialUser];
messageReactionRemove: [reaction: MessageReaction, user: User | PartialUser];
messageUpdate: [oldMessage: Message | PartialMessage, newMessage: Message | PartialMessage];
messageDeleteBulk: [messages: Collection<Snowflake, PartialDataType<Partials>['message']>];
messageReactionAdd: [message: MessageReaction, user: PartialDataType<Partials>['user']];
messageReactionRemove: [reaction: MessageReaction, user: PartialDataType<Partials>['user']];
messageUpdate: [oldMessage: PartialDataType<Partials>['message'], newMessage: PartialDataType<Partials>['message']];
presenceUpdate: [oldPresence: Presence | undefined, newPresence: Presence];
rateLimit: [rateLimitData: RateLimitData];
invalidRequestWarning: [invalidRequestWarningData: InvalidRequestWarningData];
Expand All @@ -2466,8 +2499,8 @@ declare module 'discord.js' {
roleCreate: [role: Role];
roleDelete: [role: Role];
roleUpdate: [oldRole: Role, newRole: Role];
typingStart: [channel: Channel | PartialDMChannel, user: User | PartialUser];
userUpdate: [oldUser: User | PartialUser, newUser: User];
typingStart: [channel: PartialDataType<Partials>['channel'], user: PartialDataType<Partials>['user']];
userUpdate: [oldUser: PartialDataType<Partials>['user'], newUser: User];
voiceStateUpdate: [oldState: VoiceState, newState: VoiceState];
webhookUpdate: [channel: TextChannel];
shardDisconnect: [closeEvent: CloseEvent, shardID: number];
Expand All @@ -2477,15 +2510,15 @@ declare module 'discord.js' {
shardResume: [shardID: number, replayedEvents: number];
}

interface ClientOptions {
interface ClientOptions<Partials extends PartialTypes = PartialTypes> {
shards?: number | number[] | 'auto';
shardCount?: number;
messageCacheMaxSize?: number;
messageCacheLifetime?: number;
messageSweepInterval?: number;
allowedMentions?: MessageMentionOptions;
partials?: Partials[];
invalidRequestWarningInterval?: number;
partials?: PartialTypes[];
restWsBridgeTimeout?: number;
restTimeOffset?: number;
restRequestTimeout?: number;
Expand Down Expand Up @@ -2518,7 +2551,7 @@ declare module 'discord.js' {
target: WebSocket;
}

type CollectorFilter = (...args: any[]) => boolean | Promise<boolean>;
type CollectorFilter<T extends unknown[] = any[]> = (...args: T) => boolean | Promise<boolean>;

interface CollectorOptions {
time?: number;
Expand Down Expand Up @@ -3230,6 +3263,13 @@ declare module 'discord.js' {

type PartialTypes = 'USER' | 'CHANNEL' | 'GUILD_MEMBER' | 'MESSAGE' | 'REACTION';

interface PartialDataType<Partials extends PartialTypes> {
user: Partials extends 'USER' ? User | PartialUser : User;
channel: Partials extends 'CHANNEL' ? Channel | PartialDMChannel : Channel;
guildMember: Partials extends 'GUILD_MEMBER' ? GuildMember | PartialGuildMember : GuildMember;
message: Partials extends 'MESSAGE' ? Message | PartialMessage : PartialMessage;
}

interface PartialUser extends Omit<Partialize<User, 'bot' | 'flags' | 'system' | 'tag' | 'username'>, 'deleted'> {
bot: User['bot'];
flags: User['flags'];
Expand Down