types: message component cached props narrowing (#6809)

This commit is contained in:
Suneet Tipirneni
2021-10-12 15:11:37 -04:00
committed by GitHub
parent 6898fa3b37
commit b541d0a524
3 changed files with 62 additions and 29 deletions

1
package-lock.json generated
View File

@@ -5,6 +5,7 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "discord.js",
"version": "13.3.0-dev", "version": "13.3.0-dev",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {

64
typings/index.d.ts vendored
View File

@@ -276,14 +276,6 @@ export type GuildCacheMessage<Cached extends GuildCacheState> = CacheTypeReducer
Message | APIMessage Message | APIMessage
>; >;
export interface BaseGuildCommandInteraction<Cached extends GuildCacheState = GuildCacheState>
extends GuildInteraction<Cached> {
deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
fetchReply(): Promise<GuildCacheMessage<Cached>>;
reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
}
export abstract class BaseCommandInteraction extends Interaction { export abstract class BaseCommandInteraction extends Interaction {
public readonly command: ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null; public readonly command: ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null;
public readonly channel: TextBasedChannels | null; public readonly channel: TextBasedChannels | null;
@@ -294,9 +286,9 @@ export abstract class BaseCommandInteraction extends Interaction {
public ephemeral: boolean | null; public ephemeral: boolean | null;
public replied: boolean; public replied: boolean;
public webhook: InteractionWebhook; public webhook: InteractionWebhook;
public inGuild(): this is BaseGuildCommandInteraction<'present'> & this; public inGuild(): this is InteractionResponses<'present'> & this;
public inCachedGuild(): this is BaseGuildCommandInteraction<'cached'> & this; public inCachedGuild(): this is InteractionResponses<'cached'> & this;
public inRawGuild(): this is BaseGuildCommandInteraction<'raw'> & this; public inRawGuild(): this is InteractionResponses<'raw'> & this;
public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<Message | APIMessage>; public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<Message | APIMessage>;
public deferReply(options?: InteractionDeferReplyOptions): Promise<void>; public deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
public deleteReply(): Promise<void>; public deleteReply(): Promise<void>;
@@ -312,6 +304,21 @@ export abstract class BaseCommandInteraction extends Interaction {
private transformResolved(resolved: APIApplicationCommandInteractionData['resolved']): CommandInteractionResolvedData; 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<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 abstract class BaseGuild extends Base { export abstract class BaseGuild extends Base {
protected constructor(client: Client, data: RawBaseGuildData); protected constructor(client: Client, data: RawBaseGuildData);
public readonly createdAt: Date; public readonly createdAt: Date;
@@ -599,10 +606,7 @@ export abstract class Collector<K, V, F extends unknown[] = []> extends EventEmi
public once(event: 'end', listener: (collected: Collection<K, V>, reason: string) => Awaitable<void>): this; public once(event: 'end', listener: (collected: Collection<K, V>, reason: string) => Awaitable<void>): this;
} }
export type GuildCommandInteraction<Cached extends GuildCacheState = GuildCacheState> = export class CommandInteraction extends BaseCommandInteraction {
BaseGuildCommandInteraction<Cached> & CommandInteraction;
export class CommandInteraction extends BaseCommandInteraction implements GuildCachedInteraction<CommandInteraction> {
public options: CommandInteractionOptionResolver; public options: CommandInteractionOptionResolver;
public toString(): string; public toString(): string;
} }
@@ -662,20 +666,7 @@ export class CommandInteractionOptionResolver {
public getMessage(name: string, required: true): NonNullable<CommandInteractionOption['message']>; public getMessage(name: string, required: true): NonNullable<CommandInteractionOption['message']>;
public getMessage(name: string, required?: boolean): NonNullable<CommandInteractionOption['message']> | null; public getMessage(name: string, required?: boolean): NonNullable<CommandInteractionOption['message']> | null;
} }
export class ContextMenuInteraction extends BaseCommandInteraction {
export type GuildContextMenuInteraction<Cached extends GuildCacheState = GuildCacheState> =
BaseGuildCommandInteraction<Cached> & ContextMenuInteraction;
export interface GuildCachedInteraction<T> {
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<ContextMenuInteraction>
{
public options: CommandInteractionOptionResolver; public options: CommandInteractionOptionResolver;
public targetId: Snowflake; public targetId: Snowflake;
public targetType: Exclude<ApplicationCommandType, 'CHAT_INPUT'>; public targetType: Exclude<ApplicationCommandType, 'CHAT_INPUT'>;
@@ -1128,6 +1119,18 @@ export class Interaction extends Base {
public isSelectMenu(): this is SelectMenuInteraction; public isSelectMenu(): this is SelectMenuInteraction;
} }
export interface InteractionResponses<Cached extends GuildCacheState = GuildCacheState>
extends GuildInteraction<Cached> {
deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
deleteReply(): Promise<void>;
fetchReply(): Promise<GuildCacheMessage<Cached>>;
reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
}
export class InteractionCollector<T extends Interaction> extends Collector<Snowflake, T> { export class InteractionCollector<T extends Interaction> extends Collector<Snowflake, T> {
public constructor(client: Client, options?: InteractionCollectorOptions<T>); public constructor(client: Client, options?: InteractionCollectorOptions<T>);
private _handleMessageDeletion(message: Message): void; private _handleMessageDeletion(message: Message): void;
@@ -1421,6 +1424,9 @@ export class MessageComponentInteraction extends Interaction {
public message: Message | APIMessage; public message: Message | APIMessage;
public replied: boolean; public replied: boolean;
public webhook: InteractionWebhook; 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<Message | APIMessage>; public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<Message | APIMessage>;
public deferReply(options?: InteractionDeferReplyOptions): Promise<void>; public deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
public deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<Message | APIMessage>; public deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<Message | APIMessage>;

View File

@@ -26,6 +26,7 @@ import {
DMChannel, DMChannel,
Guild, Guild,
GuildApplicationCommandManager, GuildApplicationCommandManager,
GuildCached,
GuildChannelManager, GuildChannelManager,
GuildEmoji, GuildEmoji,
GuildEmojiManager, GuildEmojiManager,
@@ -852,12 +853,22 @@ declare const booleanValue: boolean;
if (interaction.inGuild()) assertType<Snowflake>(interaction.guildId); if (interaction.inGuild()) assertType<Snowflake>(interaction.guildId);
client.on('interactionCreate', async interaction => { client.on('interactionCreate', async interaction => {
const consumeCachedCommand = (_i: GuildCached<CommandInteraction>) => {};
const consumeCachedInteraction = (_i: GuildCached<Interaction>) => {};
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<GuildMember>(interaction.member); assertType<GuildMember>(interaction.member);
// @ts-expect-error
consumeCachedCommand(interaction);
consumeCachedInteraction(interaction);
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<APIInteractionGuildMember>(interaction.member); assertType<APIInteractionGuildMember>(interaction.member);
// @ts-expect-error
consumeCachedInteraction(interaction);
} else { } else {
assertType<APIGuildMember | GuildMember | null>(interaction.member); assertType<APIGuildMember | GuildMember | null>(interaction.member);
// @ts-expect-error
consumeCachedInteraction(interaction);
} }
if (interaction.isContextMenu()) { if (interaction.isContextMenu()) {
@@ -865,6 +876,7 @@ client.on('interactionCreate', async interaction => {
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<ContextMenuInteraction>(interaction); assertType<ContextMenuInteraction>(interaction);
assertType<Guild>(interaction.guild); assertType<Guild>(interaction.guild);
consumeCachedCommand(interaction);
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<ContextMenuInteraction>(interaction); assertType<ContextMenuInteraction>(interaction);
assertType<null>(interaction.guild); assertType<null>(interaction.guild);
@@ -879,12 +891,15 @@ client.on('interactionCreate', async interaction => {
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<ButtonInteraction>(interaction); assertType<ButtonInteraction>(interaction);
assertType<Guild>(interaction.guild); assertType<Guild>(interaction.guild);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<ButtonInteraction>(interaction); assertType<ButtonInteraction>(interaction);
assertType<null>(interaction.guild); assertType<null>(interaction.guild);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<ButtonInteraction>(interaction); assertType<ButtonInteraction>(interaction);
assertType<Guild | null>(interaction.guild); assertType<Guild | null>(interaction.guild);
assertType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true }));
} }
} }
@@ -893,12 +908,15 @@ client.on('interactionCreate', async interaction => {
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<MessageComponentInteraction>(interaction); assertType<MessageComponentInteraction>(interaction);
assertType<Guild>(interaction.guild); assertType<Guild>(interaction.guild);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<MessageComponentInteraction>(interaction); assertType<MessageComponentInteraction>(interaction);
assertType<null>(interaction.guild); assertType<null>(interaction.guild);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<MessageComponentInteraction>(interaction); assertType<MessageComponentInteraction>(interaction);
assertType<Guild | null>(interaction.guild); assertType<Guild | null>(interaction.guild);
assertType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true }));
} }
} }
@@ -907,23 +925,31 @@ client.on('interactionCreate', async interaction => {
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<SelectMenuInteraction>(interaction); assertType<SelectMenuInteraction>(interaction);
assertType<Guild>(interaction.guild); assertType<Guild>(interaction.guild);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<SelectMenuInteraction>(interaction); assertType<SelectMenuInteraction>(interaction);
assertType<null>(interaction.guild); assertType<null>(interaction.guild);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<SelectMenuInteraction>(interaction); assertType<SelectMenuInteraction>(interaction);
assertType<Guild | null>(interaction.guild); assertType<Guild | null>(interaction.guild);
assertType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true }));
} }
} }
if (interaction.isCommand()) { if (interaction.isCommand()) {
if (interaction.inRawGuild()) { if (interaction.inRawGuild()) {
// @ts-expect-error
consumeCachedCommand(interaction);
assertType<CommandInteraction>(interaction); assertType<CommandInteraction>(interaction);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true })); assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inCachedGuild()) { } else if (interaction.inCachedGuild()) {
consumeCachedCommand(interaction);
assertType<CommandInteraction>(interaction); assertType<CommandInteraction>(interaction);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true })); assertType<Promise<Message>>(interaction.reply({ fetchReply: true }));
} else { } else {
// @ts-expect-error
consumeCachedCommand(interaction);
assertType<CommandInteraction>(interaction); assertType<CommandInteraction>(interaction);
assertType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true })); assertType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true }));
} }