mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
types: allow message cached props to be narrowed (#6838)
Co-authored-by: Almeida <almeidx@pm.me> Co-authored-by: Antonio Román <kyradiscord@gmail.com> Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
This commit is contained in:
@@ -889,6 +889,14 @@ class Message extends Base {
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this message is from a guild.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
inGuild() {
|
||||
return Boolean(this.guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* When concatenated with a string, this automatically concatenates the message's content instead of the object.
|
||||
* @returns {string}
|
||||
|
||||
72
typings/index.d.ts
vendored
72
typings/index.d.ts
vendored
@@ -270,7 +270,7 @@ export class BaseClient extends EventEmitter {
|
||||
|
||||
export type GuildCacheMessage<Cached extends GuildCacheState> = CacheTypeReducer<
|
||||
Cached,
|
||||
Message,
|
||||
GuildMessage<Cached> & Message,
|
||||
APIMessage,
|
||||
Message | APIMessage,
|
||||
Message | APIMessage
|
||||
@@ -315,10 +315,9 @@ export type CacheHelper<
|
||||
Cached extends GuildCacheState,
|
||||
> = T extends InteractionResponsesResolvable ? InteractionResponses<Cached> & T : GuildInteraction<Cached> & T;
|
||||
|
||||
export type GuildCached<T extends Interaction> = CacheHelper<T, 'cached'>;
|
||||
export type GuildRaw<T extends Interaction> = CacheHelper<T, 'raw'>;
|
||||
export type GuildPresent<T extends Interaction> = CacheHelper<T, 'present'>;
|
||||
|
||||
export type CachedInteraction<T extends Interaction = Interaction> = CacheHelper<T, 'cached'>;
|
||||
export type RawInteraction<T extends Interaction = Interaction> = CacheHelper<T, 'raw'>;
|
||||
export type PresentInteraction<T extends Interaction = Interaction> = CacheHelper<T, 'present'>;
|
||||
export abstract class BaseGuild extends Base {
|
||||
protected constructor(client: Client, data: RawBaseGuildData);
|
||||
public readonly createdAt: Date;
|
||||
@@ -1242,8 +1241,8 @@ export type TaggedUnion<T, K extends keyof T, V extends T[K]> = T extends Record
|
||||
: never;
|
||||
|
||||
// This creates a map of MessageComponentTypes to their respective `InteractionCollectorOptionsResolvable` variant.
|
||||
export type CollectorOptionsTypeResolver<U extends InteractionCollectorOptionsResolvable> = {
|
||||
readonly [T in U['componentType']]: TaggedUnion<InteractionCollectorOptionsResolvable, 'componentType', T>;
|
||||
export type CollectorOptionsTypeResolver<U extends InteractionCollectorOptionsResolvable<Cached>, Cached = boolean> = {
|
||||
readonly [T in U['componentType']]: TaggedUnion<U, 'componentType', T>;
|
||||
};
|
||||
|
||||
// This basically says "Given a `InteractionCollectorOptionsResolvable` variant", I'll give the corresponding
|
||||
@@ -1254,18 +1253,23 @@ export type ConditionalInteractionCollectorType<T extends InteractionCollectorOp
|
||||
: InteractionCollector<MessageComponentInteraction>;
|
||||
|
||||
// This maps each componentType key to each variant.
|
||||
export type MappedInteractionCollectorOptions = CollectorOptionsTypeResolver<InteractionCollectorOptionsResolvable>;
|
||||
export type MappedInteractionCollectorOptions<Cached = boolean> = CollectorOptionsTypeResolver<
|
||||
InteractionCollectorOptionsResolvable<Cached>,
|
||||
Cached
|
||||
>;
|
||||
|
||||
// Converts mapped types to complimentary collector types.
|
||||
export type InteractionCollectorReturnType<T extends MessageComponentType | MessageComponentTypes | undefined> =
|
||||
T extends MessageComponentType | MessageComponentTypes
|
||||
? ConditionalInteractionCollectorType<MappedInteractionCollectorOptions[T]>
|
||||
: InteractionCollector<MessageComponentInteraction>;
|
||||
export type InteractionCollectorReturnType<
|
||||
T extends MessageComponentType | MessageComponentTypes | undefined,
|
||||
Cached extends boolean = false,
|
||||
> = T extends MessageComponentType | MessageComponentTypes
|
||||
? ConditionalInteractionCollectorType<MappedInteractionCollectorOptions<Cached>[T]>
|
||||
: InteractionCollector<MessageComponentInteraction>;
|
||||
|
||||
export type InteractionExtractor<T extends MessageComponentType | MessageComponentTypes | undefined> = T extends
|
||||
| MessageComponentType
|
||||
| MessageComponentTypes
|
||||
? MappedInteractionCollectorOptions[T] extends InteractionCollectorOptions<infer Item>
|
||||
? MappedInteractionCollectorOptions<false>[T] extends InteractionCollectorOptions<infer Item>
|
||||
? Item
|
||||
: never
|
||||
: MessageComponentInteraction;
|
||||
@@ -1281,6 +1285,23 @@ export type AwaitMessageCollectorOptionsParams<T extends MessageComponentType |
|
||||
keyof AwaitMessageComponentOptions<any>
|
||||
>;
|
||||
|
||||
export type GuildTextBasedChannel = Exclude<TextBasedChannels, PartialDMChannel | DMChannel>;
|
||||
|
||||
export type CachedMessage = GuildMessage<'cached'> & Message;
|
||||
export interface GuildMessage<Cached extends GuildCacheState = GuildCacheState> {
|
||||
awaitMessageComponent<
|
||||
T extends MessageComponentType | MessageComponentTypes | undefined = MessageComponentTypes.ACTION_ROW,
|
||||
>(
|
||||
options?: AwaitMessageCollectorOptionsParams<T>,
|
||||
): Promise<InteractionResponses<Cached> & InteractionExtractor<T>>;
|
||||
|
||||
createMessageComponentCollector<T extends MessageComponentType | MessageComponentTypes | undefined = undefined>(
|
||||
options?: MessageCollectorOptionsParams<T>,
|
||||
): InteractionCollectorReturnType<T, true>;
|
||||
|
||||
readonly channel: CacheTypeReducer<Cached, GuildTextBasedChannel>;
|
||||
}
|
||||
|
||||
export class Message extends Base {
|
||||
private constructor(client: Client, data: RawMessageData);
|
||||
private _patch(data: RawPartialMessageData | RawMessageData): void;
|
||||
@@ -1350,6 +1371,7 @@ export class Message extends Base {
|
||||
public toJSON(): unknown;
|
||||
public toString(): string;
|
||||
public unpin(): Promise<Message>;
|
||||
public inGuild(): this is GuildMessage<'cached'> & this;
|
||||
}
|
||||
|
||||
export class MessageActionRow extends BaseMessageComponent {
|
||||
@@ -4247,23 +4269,31 @@ export interface InteractionCollectorOptions<T extends Interaction> extends Coll
|
||||
message?: Message | APIMessage;
|
||||
}
|
||||
|
||||
export interface ButtonInteractionCollectorOptions extends MessageComponentCollectorOptions<ButtonInteraction> {
|
||||
export interface ButtonInteractionCollectorOptions<Cached = boolean>
|
||||
extends MessageComponentCollectorOptions<
|
||||
Cached extends true ? CachedInteraction<ButtonInteraction> : ButtonInteraction
|
||||
> {
|
||||
componentType: 'BUTTON' | MessageComponentTypes.BUTTON;
|
||||
}
|
||||
|
||||
export interface SelectMenuInteractionCollectorOptions extends MessageComponentCollectorOptions<SelectMenuInteraction> {
|
||||
export interface SelectMenuInteractionCollectorOptions<Cached = boolean>
|
||||
extends MessageComponentCollectorOptions<
|
||||
Cached extends true ? CachedInteraction<SelectMenuInteraction> : SelectMenuInteraction
|
||||
> {
|
||||
componentType: 'SELECT_MENU' | MessageComponentTypes.SELECT_MENU;
|
||||
}
|
||||
|
||||
export interface MessageInteractionCollectorOptions
|
||||
extends MessageComponentCollectorOptions<MessageComponentInteraction> {
|
||||
export interface MessageInteractionCollectorOptions<Cached = boolean>
|
||||
extends MessageComponentCollectorOptions<
|
||||
Cached extends true ? CachedInteraction<MessageComponentInteraction> : MessageComponentInteraction
|
||||
> {
|
||||
componentType: 'ACTION_ROW' | MessageComponentTypes.ACTION_ROW;
|
||||
}
|
||||
|
||||
export type InteractionCollectorOptionsResolvable =
|
||||
| MessageInteractionCollectorOptions
|
||||
| SelectMenuInteractionCollectorOptions
|
||||
| ButtonInteractionCollectorOptions;
|
||||
export type InteractionCollectorOptionsResolvable<Cached = boolean> =
|
||||
| MessageInteractionCollectorOptions<Cached>
|
||||
| SelectMenuInteractionCollectorOptions<Cached>
|
||||
| ButtonInteractionCollectorOptions<Cached>;
|
||||
|
||||
export interface InteractionDeferReplyOptions {
|
||||
ephemeral?: boolean;
|
||||
|
||||
@@ -33,15 +33,19 @@ import {
|
||||
DMChannel,
|
||||
Guild,
|
||||
GuildApplicationCommandManager,
|
||||
GuildCached,
|
||||
CachedInteraction,
|
||||
GuildChannelManager,
|
||||
GuildEmoji,
|
||||
GuildEmojiManager,
|
||||
GuildMember,
|
||||
GuildMessage,
|
||||
GuildResolvable,
|
||||
GuildTextBasedChannel,
|
||||
GuildTextChannelResolvable,
|
||||
Intents,
|
||||
Interaction,
|
||||
InteractionCollector,
|
||||
InteractionResponses,
|
||||
LimitedCollection,
|
||||
Message,
|
||||
MessageActionRow,
|
||||
@@ -73,6 +77,7 @@ import {
|
||||
Typing,
|
||||
User,
|
||||
VoiceChannel,
|
||||
CachedMessage,
|
||||
} from '.';
|
||||
import { ApplicationCommandOptionTypes } from './enums';
|
||||
|
||||
@@ -492,6 +497,22 @@ client.on('messageCreate', async message => {
|
||||
assertIsMessage(channel.send({ embeds: [embed] }));
|
||||
assertIsMessage(channel.send({ embeds: [embed], files: [attachment] }));
|
||||
|
||||
if (message.inGuild()) {
|
||||
assertType<CachedMessage>(message);
|
||||
const component = await message.awaitMessageComponent({ componentType: 'BUTTON' });
|
||||
assertType<InteractionResponses<'cached'>>(component);
|
||||
assertType<Promise<CachedMessage>>(component.reply({ fetchReply: true }));
|
||||
|
||||
const buttonCollector = message.createMessageComponentCollector({ componentType: 'BUTTON' });
|
||||
assertType<InteractionCollector<CachedInteraction<ButtonInteraction>>>(buttonCollector);
|
||||
assertType<GuildTextBasedChannel>(message.channel);
|
||||
}
|
||||
|
||||
assertType<TextBasedChannels>(message.channel);
|
||||
|
||||
// @ts-expect-error
|
||||
assertType<GuildTextBasedChannel>(message.channel);
|
||||
|
||||
// @ts-expect-error
|
||||
channel.send();
|
||||
// @ts-expect-error
|
||||
@@ -876,8 +897,8 @@ declare const booleanValue: boolean;
|
||||
if (interaction.inGuild()) assertType<Snowflake>(interaction.guildId);
|
||||
|
||||
client.on('interactionCreate', async interaction => {
|
||||
const consumeCachedCommand = (_i: GuildCached<CommandInteraction>) => {};
|
||||
const consumeCachedInteraction = (_i: GuildCached<Interaction>) => {};
|
||||
const consumeCachedCommand = (_i: CachedInteraction<CommandInteraction>) => {};
|
||||
const consumeCachedInteraction = (_i: CachedInteraction<Interaction>) => {};
|
||||
|
||||
if (interaction.inCachedGuild()) {
|
||||
assertType<GuildMember>(interaction.member);
|
||||
@@ -969,6 +990,12 @@ client.on('interactionCreate', async interaction => {
|
||||
assertType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test'));
|
||||
assertType<APIInteractionDataResolvedGuildMember>(interaction.options.getMember('test', true));
|
||||
} else if (interaction.inCachedGuild()) {
|
||||
const msg = await interaction.reply({ fetchReply: true });
|
||||
const btn = await msg.awaitMessageComponent({ componentType: 'BUTTON' });
|
||||
|
||||
assertType<Message>(msg);
|
||||
assertType<CachedInteraction<ButtonInteraction>>(btn);
|
||||
|
||||
consumeCachedCommand(interaction);
|
||||
assertType<GuildMember>(interaction.options.getMember('test', true));
|
||||
assertType<GuildMember | null>(interaction.options.getMember('test'));
|
||||
|
||||
Reference in New Issue
Block a user