Skip to content

Commit

Permalink
Typeguards for interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
DonovanDMC committed Jan 20, 2024
1 parent b0bc901 commit 8250ffe
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
29 changes: 22 additions & 7 deletions lib/structures/CommandInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ import { UncachedError } from "../util/Errors";
import MessageInteractionResponse, { type FollowupMessageInteractionResponse, type InitialMessagedInteractionResponse } from "../util/interactions/MessageInteractionResponse";

/** Represents a command interaction. */
export default class CommandInteraction<T extends AnyInteractionChannel | Uncached = AnyInteractionChannel | Uncached> extends Interaction {
export default class CommandInteraction<T extends AnyInteractionChannel | Uncached = AnyInteractionChannel | Uncached, C extends ApplicationCommandTypes = ApplicationCommandTypes> extends Interaction {
private _cachedChannel!: T extends AnyInteractionChannel ? T : undefined;
private _cachedGuild?: T extends AnyTextableGuildChannel ? Guild : Guild | null;
/** The permissions the bot has in the channel this interaction was sent from, if this interaction is sent from a guild. */
appPermissions: T extends AnyTextableGuildChannel ? Permission : Permission | undefined;
/** The ID of the channel this interaction was sent from. */
channelID: string;
/** The data associated with the interaction. */
data: ApplicationCommandInteractionData;
data: ApplicationCommandInteractionData<T, C>;
/** The entitlements for the user that created this interaction, and the guild it was created in. */
entitlements: Array<Entitlement | TestEntitlement>;
/** The id of the guild this interaction was sent from, if applicable. */
Expand Down Expand Up @@ -130,16 +130,16 @@ export default class CommandInteraction<T extends AnyInteractionChannel | Uncach
name: data.data.name,
options: new InteractionOptionsWrapper(data.data.options ?? [], resolved ?? null),
resolved,
target: undefined,
targetID: data.data.target_id,
type: data.data.type
target: null as never,
targetID: data.data.target_id as never,
type: data.data.type as C
};

if (this.data.targetID) {
if (this.data.type === ApplicationCommandTypes.USER) {
this.data.target = resolved.users.get(this.data.targetID);
this.data.target = resolved.users.get(this.data.targetID) as never;
} else if (this.data.type === ApplicationCommandTypes.MESSAGE) {
this.data.target = resolved.messages.get(this.data.targetID);
this.data.target = resolved.messages.get(this.data.targetID) as never;
}
}
}
Expand Down Expand Up @@ -272,6 +272,21 @@ export default class CommandInteraction<T extends AnyInteractionChannel | Uncach
return this.guildID === null;
}

/** A type guard, checking if this command interaction is a {@link Constants~ApplicationCommandTypes.CHAT_INPUT | Chat Input} command. */
isChatInputCommand(): this is CommandInteraction<T, ApplicationCommandTypes.CHAT_INPUT> {
return this.data.type === ApplicationCommandTypes.CHAT_INPUT;
}

/** A type guard, checking if this command interaction is a {@link Constants~ApplicationCommandTypes.MESSAGE | Message} command. */
isMessageCommand(): this is CommandInteraction<T, ApplicationCommandTypes.MESSAGE> {
return this.data.type === ApplicationCommandTypes.MESSAGE;
}

/** A type guard, checking if this command interaction is a {@link Constants~ApplicationCommandTypes.USER | User} command. */
isUserCommand(): this is CommandInteraction<T, ApplicationCommandTypes.USER> {
return this.data.type === ApplicationCommandTypes.USER;
}

/** Show a "premium required" response to the user. This is an initial response, and more than one initial response cannot be used. */
async premiumRequired(): Promise<void> {
if (this.acknowledged) {
Expand Down
31 changes: 31 additions & 0 deletions lib/structures/Interaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/** @module Interaction */
import Base from "./Base";
import type ClientApplication from "./ClientApplication";
import type ICommandInteraction from "./CommandInteraction";
import type IModalSubmitInteraction from "./ModalSubmitInteraction";
import type IPingInteraction from "./PingInteraction";
import type IComponentInteraction from "./ComponentInteraction";
import type IAutocompleteInteraction from "./AutocompleteInteraction";
import type Client from "../Client";
import type {
AnyInteraction,
Expand All @@ -14,6 +19,7 @@ import type {
import { InteractionTypes } from "../Constants";
import type { JSONInteraction } from "../types/json";


/** Represents an interaction. */
export default class Interaction extends Base {
/** If this interaction has been acknowledged. */
Expand Down Expand Up @@ -62,6 +68,31 @@ export default class Interaction extends Base {
}
}

/** A type guard, checking if this interaction is an {@link AutocompleteInteraction | Autocomplete Interaction}. */
isAutocompleteInteraction(): this is IAutocompleteInteraction {
return this.type === InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE;
}

/** A type guard, checking if this interaction is a {@link CommandInteraction | Command Interaction}. */
isCommandInteraction(): this is ICommandInteraction {
return this.type === InteractionTypes.APPLICATION_COMMAND;
}

/** A type guard, checking if this interaction is a {@link ComponentInteraction | Component Interaction}. */
isComponentInteraction(): this is IComponentInteraction {
return this.type === InteractionTypes.MESSAGE_COMPONENT;
}

/** A type guard, checking if this interaction is a {@link ModalSubmitInteraction | Modal Submit Interaction}. */
isModelSubmitInteraction(): this is IModalSubmitInteraction {
return this.type === InteractionTypes.MODAL_SUBMIT;
}

/** A type guard, checking if this interaction is a {@link PingInteraction | Ping Interaction}. */
isPingInteraction(): this is IPingInteraction {
return this.type === InteractionTypes.PING;
}

override toJSON(): JSONInteraction {
return {
...super.toJSON(),
Expand Down
15 changes: 9 additions & 6 deletions lib/types/interactions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import type {
ModalActionRow,
RawAttachment,
RawInteractionResolvedChannel,
RawMessage
RawMessage,
AnyInteractionChannel
} from "./channels";
import type { InteractionMember, RawMember, RawRole } from "./guilds";
import type { RawUser } from "./users";
Expand Down Expand Up @@ -131,18 +132,18 @@ export interface RawApplicationCommandInteractionData {
target_id?: string;
type: ApplicationCommandTypes;
}
export interface ApplicationCommandInteractionData {
export interface ApplicationCommandInteractionData<T extends AnyInteractionChannel | Uncached = AnyInteractionChannel | Uncached, C extends ApplicationCommandTypes = ApplicationCommandTypes> {
guildID?: string;
id: string;
name: string;
options: InteractionOptionsWrapper;
resolved: ApplicationCommandInteractionResolvedData;
target?: User | Message;
targetID?: string;
type: ApplicationCommandTypes;
target: C extends ApplicationCommandTypes.CHAT_INPUT ? null : C extends ApplicationCommandTypes.USER ? User : C extends ApplicationCommandTypes.MESSAGE ? Message<T> : User | Message<T> | null;
targetID: C extends ApplicationCommandTypes.CHAT_INPUT ? null : C extends ApplicationCommandTypes.USER | ApplicationCommandTypes.MESSAGE ? string : string | null;
type: C;
}
export interface RawAutocompleteInteractionData extends Omit<RawApplicationCommandInteractionData, "resolved" | "target_id"> {}
export interface AutocompleteInteractionData extends Omit<ApplicationCommandInteractionData, "resolved" | "targetID"> {}
export interface AutocompleteInteractionData extends Omit<ApplicationCommandInteractionData, "resolved" | "target" | "targetID"> {}

export interface RawMessageComponentInteractionResolvedData {
channels?: Record<string, RawInteractionResolvedChannel>;
Expand Down Expand Up @@ -371,3 +372,5 @@ T extends ModalSubmitTextInputComponent ? RawModalSubmitTextInputComponent :
export type ModalSubmitComponentsActionRow = ModalComponentsActionRow<ModalSubmitComponents>;
export type ModalSubmitComponents = ModalSubmitTextInputComponent;
export interface ModalSubmitTextInputComponent extends ModalSubmitComponentsStringValue<ComponentTypes.TEXT_INPUT> {}

export type ApplicationCommandTypesWithTarget = ApplicationCommandTypes.USER | ApplicationCommandTypes.MESSAGE;

0 comments on commit 8250ffe

Please sign in to comment.