From dea68400a38edb90b8b4242d64be14968943130d Mon Sep 17 00:00:00 2001 From: Vlad Frangu Date: Fri, 6 Sep 2024 10:16:38 +0300 Subject: [PATCH] fix: type guard for sendable text-based channels (#10482) * fix: type-guard for sendable text-based channels * chore: suggested change * Update packages/discord.js/typings/index.test-d.ts Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> * fix: make isSendable strictly check for `.send` * fix: tests --------- Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> --- .../discord.js/src/structures/BaseChannel.js | 8 ++++++++ packages/discord.js/src/util/Constants.js | 17 ++++++++++++++++- packages/discord.js/typings/index.d.ts | 8 +++++++- packages/discord.js/typings/index.test-d.ts | 15 +++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index 2b179d3574bc..ebb95682819c 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -155,6 +155,14 @@ class BaseChannel extends Base { return 'availableTags' in this; } + /** + * Indicates whether this channel is sendable. + * @returns {boolean} + */ + isSendable() { + return 'send' in this; + } + toJSON(...props) { return super.toJSON({ createdTimestamp: true }, ...props); } diff --git a/packages/discord.js/src/util/Constants.js b/packages/discord.js/src/util/Constants.js index e64d807e4300..8babdfdbea68 100644 --- a/packages/discord.js/src/util/Constants.js +++ b/packages/discord.js/src/util/Constants.js @@ -117,9 +117,24 @@ exports.GuildTextBasedChannelTypes = [ * * {@link ChannelType.PrivateThread} * * {@link ChannelType.GuildVoice} * * {@link ChannelType.GuildStageVoice} + * * {@link ChannelType.GroupDM} * @typedef {ChannelType[]} TextBasedChannelTypes */ -exports.TextBasedChannelTypes = [...exports.GuildTextBasedChannelTypes, ChannelType.DM]; +exports.TextBasedChannelTypes = [...exports.GuildTextBasedChannelTypes, ChannelType.DM, ChannelType.GroupDM]; + +/** + * The types of channels that are text-based and can have messages sent into. The available types are: + * * {@link ChannelType.DM} + * * {@link ChannelType.GuildText} + * * {@link ChannelType.GuildAnnouncement} + * * {@link ChannelType.AnnouncementThread} + * * {@link ChannelType.PublicThread} + * * {@link ChannelType.PrivateThread} + * * {@link ChannelType.GuildVoice} + * * {@link ChannelType.GuildStageVoice} + * @typedef {ChannelType[]} SendableChannels + */ +exports.SendableChannels = [...exports.GuildTextBasedChannelTypes, ChannelType.DM]; /** * The types of channels that are threads. The available types are: diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index cc3f0e454fc6..2ac27e78a990 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -975,6 +975,7 @@ export abstract class BaseChannel extends Base { public isDMBased(): this is PartialGroupDMChannel | DMChannel | PartialDMChannel; public isVoiceBased(): this is VoiceBasedChannel; public isThreadOnly(): this is ThreadOnlyChannel; + public isSendable(): this is SendableChannels; public toString(): ChannelMention | UserMention; } @@ -3867,6 +3868,7 @@ export const Constants: { SweeperKeys: SweeperKey[]; NonSystemMessageTypes: NonSystemMessageType[]; TextBasedChannelTypes: TextBasedChannelTypes[]; + SendableChannels: SendableChannelTypes[]; GuildTextBasedChannelTypes: GuildTextBasedChannelTypes[]; ThreadChannelTypes: ThreadChannelType[]; VoiceBasedChannelTypes: VoiceBasedChannelTypes[]; @@ -6879,11 +6881,15 @@ export type Channel = export type TextBasedChannel = Exclude, ForumChannel | MediaChannel>; +export type SendableChannels = Extract any }>; + export type TextBasedChannels = TextBasedChannel; export type TextBasedChannelTypes = TextBasedChannel['type']; -export type GuildTextBasedChannelTypes = Exclude; +export type GuildTextBasedChannelTypes = Exclude; + +export type SendableChannelTypes = SendableChannels['type']; export type VoiceBasedChannel = Extract; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 02011850550a..1f499be832d6 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -209,6 +209,7 @@ import { ApplicationEmoji, ApplicationEmojiManager, StickerPack, + SendableChannels, } from '.'; import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd'; import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders'; @@ -2593,3 +2594,17 @@ declare const poll: Poll; expectType>(await client.fetchStickerPacks()); expectType>(await client.fetchStickerPacks({})); expectType(await client.fetchStickerPacks({ packId: snowflake })); + +client.on('interactionCreate', interaction => { + if (!interaction.channel) { + return; + } + + // @ts-expect-error + interaction.channel.send(); + + if (interaction.channel.isSendable()) { + expectType(interaction.channel); + interaction.channel.send({ embeds: [] }); + } +});