From b541d0a524ea7a8a6d2ab16c92f8ec5d4b100ca6 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:11:37 -0400 Subject: [PATCH] types: message component cached props narrowing (#6809) --- package-lock.json | 1 + typings/index.d.ts | 64 +++++++++++++++++++++++++--------------------- typings/tests.ts | 26 +++++++++++++++++++ 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87a18f920..c54d5c3f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "discord.js", "version": "13.3.0-dev", "license": "Apache-2.0", "dependencies": { diff --git a/typings/index.d.ts b/typings/index.d.ts index 3f880839b..fb954f293 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -276,14 +276,6 @@ export type GuildCacheMessage = CacheTypeReducer Message | APIMessage >; -export interface BaseGuildCommandInteraction - extends GuildInteraction { - deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise>; - editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise>; - fetchReply(): Promise>; - reply(options: InteractionReplyOptions & { fetchReply: true }): Promise>; -} - export abstract class BaseCommandInteraction extends Interaction { public readonly command: ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null; public readonly channel: TextBasedChannels | null; @@ -294,9 +286,9 @@ export abstract class BaseCommandInteraction extends Interaction { public ephemeral: boolean | null; public replied: boolean; public webhook: InteractionWebhook; - public inGuild(): this is BaseGuildCommandInteraction<'present'> & this; - public inCachedGuild(): this is BaseGuildCommandInteraction<'cached'> & this; - public inRawGuild(): this is BaseGuildCommandInteraction<'raw'> & this; + public inGuild(): this is InteractionResponses<'present'> & this; + public inCachedGuild(): this is InteractionResponses<'cached'> & this; + public inRawGuild(): this is InteractionResponses<'raw'> & this; public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise; public deferReply(options?: InteractionDeferReplyOptions): Promise; public deleteReply(): Promise; @@ -312,6 +304,21 @@ export abstract class BaseCommandInteraction extends Interaction { private transformResolved(resolved: APIApplicationCommandInteractionData['resolved']): CommandInteractionResolvedData; } +export interface InteractionResponsesResolvable { + inGuild(): this is InteractionResponses<'present'> & this; + inCachedGuild(): this is InteractionResponses<'cached'> & this; + inRawGuild(): this is InteractionResponses<'raw'> & this; +} + +export type CacheHelper< + T extends Interaction, + Cached extends GuildCacheState, +> = T extends InteractionResponsesResolvable ? InteractionResponses & T : GuildInteraction & T; + +export type GuildCached = CacheHelper; +export type GuildRaw = CacheHelper; +export type GuildPresent = CacheHelper; + export abstract class BaseGuild extends Base { protected constructor(client: Client, data: RawBaseGuildData); public readonly createdAt: Date; @@ -599,10 +606,7 @@ export abstract class Collector extends EventEmi public once(event: 'end', listener: (collected: Collection, reason: string) => Awaitable): this; } -export type GuildCommandInteraction = - BaseGuildCommandInteraction & CommandInteraction; - -export class CommandInteraction extends BaseCommandInteraction implements GuildCachedInteraction { +export class CommandInteraction extends BaseCommandInteraction { public options: CommandInteractionOptionResolver; public toString(): string; } @@ -662,20 +666,7 @@ export class CommandInteractionOptionResolver { public getMessage(name: string, required: true): NonNullable; public getMessage(name: string, required?: boolean): NonNullable | null; } - -export type GuildContextMenuInteraction = - BaseGuildCommandInteraction & ContextMenuInteraction; - -export interface GuildCachedInteraction { - inGuild(): this is BaseGuildCommandInteraction<'present'> & T; - inCachedGuild(): this is BaseGuildCommandInteraction<'cached'> & T; - inRawGuild(): this is BaseGuildCommandInteraction<'raw'> & T; -} - -export class ContextMenuInteraction - extends BaseCommandInteraction - implements GuildCachedInteraction -{ +export class ContextMenuInteraction extends BaseCommandInteraction { public options: CommandInteractionOptionResolver; public targetId: Snowflake; public targetType: Exclude; @@ -1128,6 +1119,18 @@ export class Interaction extends Base { public isSelectMenu(): this is SelectMenuInteraction; } +export interface InteractionResponses + extends GuildInteraction { + deferReply(options?: InteractionDeferReplyOptions): Promise; + deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise>; + editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise>; + deleteReply(): Promise; + fetchReply(): Promise>; + reply(options: InteractionReplyOptions & { fetchReply: true }): Promise>; + reply(options: string | MessagePayload | InteractionReplyOptions): Promise; + followUp(options: string | MessagePayload | InteractionReplyOptions): Promise>; +} + export class InteractionCollector extends Collector { public constructor(client: Client, options?: InteractionCollectorOptions); private _handleMessageDeletion(message: Message): void; @@ -1421,6 +1424,9 @@ export class MessageComponentInteraction extends Interaction { public message: Message | APIMessage; public replied: boolean; public webhook: InteractionWebhook; + public inGuild(): this is InteractionResponses<'present'> & this; + public inCachedGuild(): this is InteractionResponses<'cached'> & this; + public inRawGuild(): this is InteractionResponses<'raw'> & this; public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise; public deferReply(options?: InteractionDeferReplyOptions): Promise; public deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise; diff --git a/typings/tests.ts b/typings/tests.ts index 33a6b04d8..03aa9898b 100644 --- a/typings/tests.ts +++ b/typings/tests.ts @@ -26,6 +26,7 @@ import { DMChannel, Guild, GuildApplicationCommandManager, + GuildCached, GuildChannelManager, GuildEmoji, GuildEmojiManager, @@ -852,12 +853,22 @@ declare const booleanValue: boolean; if (interaction.inGuild()) assertType(interaction.guildId); client.on('interactionCreate', async interaction => { + const consumeCachedCommand = (_i: GuildCached) => {}; + const consumeCachedInteraction = (_i: GuildCached) => {}; + if (interaction.inCachedGuild()) { assertType(interaction.member); + // @ts-expect-error + consumeCachedCommand(interaction); + consumeCachedInteraction(interaction); } else if (interaction.inRawGuild()) { assertType(interaction.member); + // @ts-expect-error + consumeCachedInteraction(interaction); } else { assertType(interaction.member); + // @ts-expect-error + consumeCachedInteraction(interaction); } if (interaction.isContextMenu()) { @@ -865,6 +876,7 @@ client.on('interactionCreate', async interaction => { if (interaction.inCachedGuild()) { assertType(interaction); assertType(interaction.guild); + consumeCachedCommand(interaction); } else if (interaction.inRawGuild()) { assertType(interaction); assertType(interaction.guild); @@ -879,12 +891,15 @@ client.on('interactionCreate', async interaction => { if (interaction.inCachedGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inRawGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } } @@ -893,12 +908,15 @@ client.on('interactionCreate', async interaction => { if (interaction.inCachedGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inRawGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } } @@ -907,23 +925,31 @@ client.on('interactionCreate', async interaction => { if (interaction.inCachedGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inRawGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inGuild()) { assertType(interaction); assertType(interaction.guild); + assertType>(interaction.reply({ fetchReply: true })); } } if (interaction.isCommand()) { if (interaction.inRawGuild()) { + // @ts-expect-error + consumeCachedCommand(interaction); assertType(interaction); assertType>(interaction.reply({ fetchReply: true })); } else if (interaction.inCachedGuild()) { + consumeCachedCommand(interaction); assertType(interaction); assertType>(interaction.reply({ fetchReply: true })); } else { + // @ts-expect-error + consumeCachedCommand(interaction); assertType(interaction); assertType>(interaction.reply({ fetchReply: true })); }