From da05a8856b11cc1bf0df424c88a1cf9573e5b654 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Mon, 17 Jan 2022 14:17:34 -0500 Subject: [PATCH] feat(interaction): add `isRepliable` type guard (#7259) Co-authored-by: Almeida Co-authored-by: Rodry <38259440+ImRodry@users.noreply.github.com> --- packages/discord.js/src/structures/Interaction.js | 8 ++++++++ packages/discord.js/typings/index.d.ts | 12 ++++++++++++ packages/discord.js/typings/index.test-d.ts | 11 +++++++++++ 3 files changed, 31 insertions(+) diff --git a/packages/discord.js/src/structures/Interaction.js b/packages/discord.js/src/structures/Interaction.js index 03a7606f3..b8bc14939 100644 --- a/packages/discord.js/src/structures/Interaction.js +++ b/packages/discord.js/src/structures/Interaction.js @@ -226,6 +226,14 @@ class Interaction extends Base { ComponentType[this.componentType] === ComponentType.SelectMenu ); } + + /** + * Indicates whether this interaction can be replied to. + * @returns {boolean} + */ + isRepliable() { + return ![InteractionType.Ping, InteractionType.ApplicationCommandAutocomplete].includes(InteractionType[this.type]); + } } module.exports = Interaction; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 671285462..b3c0fd179 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -324,6 +324,17 @@ export type GuildCacheMessage = CacheTypeReducer< Message | APIMessage >; +export interface InteractionResponseFields { + reply(options: InteractionReplyOptions & { fetchReply: true }): Promise>; + reply(options: string | MessagePayload | InteractionReplyOptions): Promise; + deleteReply(): Promise; + editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise>; + deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise>; + deferReply(options?: InteractionDeferReplyOptions): Promise; + fetchReply(): Promise>; + followUp(options: string | MessagePayload | InteractionReplyOptions): Promise>; +} + export abstract class CommandInteraction extends Interaction { public readonly command: ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null; public options: Omit< @@ -1327,6 +1338,7 @@ export class Interaction extends Base { public isUserContextMenuCommand(): this is UserContextMenuCommandInteraction; public isMessageComponent(): this is MessageComponentInteraction; public isSelectMenu(): this is SelectMenuInteraction; + public isRepliable(): this is this & InteractionResponseFields; } export class InteractionCollector extends Collector { diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index f8e3ceab9..140c58343 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -92,6 +92,7 @@ import { ButtonComponent, SelectMenuComponent, ActionRowComponent, + InteractionResponseFields, } from '.'; import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd'; @@ -1124,6 +1125,16 @@ client.on('interactionCreate', async interaction => { expectType(interaction.options.getSubcommandGroup(booleanValue)); expectType(interaction.options.getSubcommandGroup(false)); } + + if (interaction.isRepliable()) { + expectAssignable(interaction); + interaction.reply('test'); + } + + if (interaction.isChatInputCommand() && interaction.isRepliable()) { + expectAssignable(interaction); + expectAssignable(interaction); + } }); declare const shard: Shard;