Modern Discord interactions system including slash commands, context menus, button interactions, modal forms, and application command management.
Foundation for all Discord interactions with common properties and methods.
/**
* Base class for all Discord interactions
* @extends Base
*/
class BaseInteraction extends Base {
readonly id: Snowflake;
readonly applicationId: Snowflake;
readonly type: InteractionType;
readonly token: string;
readonly channelId: Snowflake | null;
readonly channel: TextBasedChannel | null;
readonly guildId: Snowflake | null;
readonly guild: Guild | null;
readonly user: User;
readonly member: GuildMember | null;
readonly version: number;
readonly appPermissions: Readonly<PermissionsBitField> | null;
readonly memberPermissions: Readonly<PermissionsBitField> | null;
readonly locale: Locale;
readonly guildLocale: Locale | null;
readonly createdAt: Date;
// Type guards
isApplicationCommand(): this is ApplicationCommandInteraction;
isAutocomplete(): this is AutocompleteInteraction;
isChatInputCommand(): this is ChatInputCommandInteraction;
isContextMenuCommand(): this is ContextMenuCommandInteraction;
isMessageComponent(): this is MessageComponentInteraction;
isButton(): this is ButtonInteraction;
isAnySelectMenu(): this is AnySelectMenuInteraction;
isModalSubmit(): this is ModalSubmitInteraction;
// Utility methods
inGuild(): this is BaseInteraction & { guildId: Snowflake; guild: Guild; member: GuildMember };
inCachedGuild(): this is BaseInteraction & { guild: Guild; member: GuildMember };
inRawGuild(): this is BaseInteraction & { guildId: Snowflake; member: APIGuildMember | null };
isRepliable(): this is BaseInteraction & InteractionResponseMixin;
}Modern slash command interactions with options and autocomplete support.
/**
* Represents a slash command interaction
* @extends CommandInteraction
*/
class ChatInputCommandInteraction extends CommandInteraction {
readonly type: InteractionType.ApplicationCommand;
readonly commandType: ApplicationCommandType.ChatInput;
readonly options: CommandInteractionOptionResolver;
toString(): string;
}
/**
* Base class for application command interactions
* @extends BaseInteraction
*/
class CommandInteraction extends BaseInteraction {
readonly commandId: Snowflake;
readonly commandName: string;
readonly commandGuildId: Snowflake | null;
// Response methods
reply(options: InteractionReplyOptions): Promise<InteractionResponse>;
editReply(options: InteractionEditReplyOptions): Promise<Message>;
deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse>;
fetchReply(): Promise<Message>;
followUp(options: InteractionReplyOptions): Promise<Message>;
deleteReply(message?: MessageResolvable | '@original'): Promise<void>;
// State checks
readonly replied: boolean;
readonly deferred: boolean;
}
/**
* Resolves and provides access to command options
*/
class CommandInteractionOptionResolver {
constructor(client: Client, options: CommandInteractionOption[], resolved: CommandInteractionResolvedData);
// Value getters
get(name: string, required: true): CommandInteractionOption;
get(name: string, required?: boolean): CommandInteractionOption | null;
getSubcommandGroup(required?: boolean): string | null;
getSubcommand(required?: boolean): string | null;
// Typed getters
getString(name: string, required: true): string;
getString(name: string, required?: boolean): string | null;
getInteger(name: string, required: true): number;
getInteger(name: string, required?: boolean): number | null;
getNumber(name: string, required: true): number;
getNumber(name: string, required?: boolean): number | null;
getBoolean(name: string, required: true): boolean;
getBoolean(name: string, required?: boolean): boolean | null;
getChannel(name: string, required: true): GuildChannel | APIInteractionDataResolvedChannel | ThreadChannel;
getChannel(name: string, required?: boolean): GuildChannel | APIInteractionDataResolvedChannel | ThreadChannel | null;
getUser(name: string, required: true): User;
getUser(name: string, required?: boolean): User | null;
getMember(name: string): GuildMember | APIInteractionDataResolvedGuildMember | null;
getRole(name: string, required: true): Role | APIRole;
getRole(name: string, required?: boolean): Role | APIRole | null;
getMentionable(name: string, required: true): User | GuildMember | APIInteractionDataResolvedGuildMember | Role | APIRole;
getMentionable(name: string, required?: boolean): User | GuildMember | APIInteractionDataResolvedGuildMember | Role | APIRole | null;
getAttachment(name: string, required: true): Attachment;
getAttachment(name: string, required?: boolean): Attachment | null;
// Focused option for autocomplete
getFocused(getFull?: false): string;
getFocused(getFull: true): AutocompleteFocusedOption;
}
interface InteractionReplyOptions extends BaseMessageOptions {
ephemeral?: boolean;
fetchReply?: boolean;
}
interface InteractionEditReplyOptions extends Omit<BaseMessageOptions, 'reply'> {
attachments?: JSONEncodable<AttachmentPayload>[];
}
interface InteractionDeferReplyOptions {
ephemeral?: boolean;
fetchReply?: boolean;
}Usage Examples:
// Handle slash command interaction
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'ping') {
await interaction.reply('Pong!');
}
if (interaction.commandName === 'userinfo') {
const user = interaction.options.getUser('user', true);
const member = interaction.options.getMember('user');
await interaction.reply({
content: `User: ${user.tag}`,
ephemeral: true
});
}
if (interaction.commandName === 'slow-command') {
// Defer reply for long operations
await interaction.deferReply();
// Do some long operation...
await new Promise(resolve => setTimeout(resolve, 5000));
await interaction.editReply('Operation completed!');
}
});
// Register slash commands
const commands = [
{
name: 'ping',
description: 'Replies with Pong!'
},
{
name: 'userinfo',
description: 'Get information about a user',
options: [
{
name: 'user',
description: 'The user to get info about',
type: ApplicationCommandOptionType.User,
required: true
}
]
}
];
await rest.put(Routes.applicationCommands(client.user.id), { body: commands });Right-click context menu commands for users and messages.
/**
* Base class for context menu command interactions
* @extends CommandInteraction
*/
class ContextMenuCommandInteraction extends CommandInteraction {
readonly commandType: ApplicationCommandType.User | ApplicationCommandType.Message;
readonly targetId: Snowflake;
}
/**
* User context menu command interaction
* @extends ContextMenuCommandInteraction
*/
class UserContextMenuCommandInteraction extends ContextMenuCommandInteraction {
readonly commandType: ApplicationCommandType.User;
readonly targetUser: User;
readonly targetMember: GuildMember | null;
}
/**
* Message context menu command interaction
* @extends ContextMenuCommandInteraction
*/
class MessageContextMenuCommandInteraction extends ContextMenuCommandInteraction {
readonly commandType: ApplicationCommandType.Message;
readonly targetMessage: Message;
}Provide dynamic autocomplete suggestions for slash command options.
/**
* Represents an autocomplete interaction
* @extends BaseInteraction
*/
class AutocompleteInteraction extends BaseInteraction {
readonly type: InteractionType.ApplicationCommandAutocomplete;
readonly commandId: Snowflake;
readonly commandName: string;
readonly commandType: ApplicationCommandType;
readonly commandGuildId: Snowflake | null;
readonly options: CommandInteractionOptionResolver;
respond(options: ApplicationCommandOptionChoiceData[]): Promise<void>;
}
interface ApplicationCommandOptionChoiceData {
name: string;
name_localizations?: LocalizationMap;
value: string | number;
}
interface AutocompleteFocusedOption {
name: string;
type: ApplicationCommandOptionType;
value: string;
focused: true;
}Usage Examples:
// Handle autocomplete interactions
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isAutocomplete()) return;
if (interaction.commandName === 'music') {
const focusedOption = interaction.options.getFocused(true);
if (focusedOption.name === 'song') {
const searchQuery = focusedOption.value;
// Search for songs matching the query
const songs = await searchSongs(searchQuery);
const choices = songs.slice(0, 25).map(song => ({
name: `${song.title} - ${song.artist}`,
value: song.id
}));
await interaction.respond(choices);
}
}
});Handle button component interactions from messages.
/**
* Represents a button interaction
* @extends MessageComponentInteraction
*/
class ButtonInteraction extends MessageComponentInteraction {
readonly componentType: ComponentType.Button;
readonly component: ButtonComponent;
update(options: InteractionUpdateOptions): Promise<InteractionResponse>;
}
/**
* Base class for message component interactions
* @extends BaseInteraction
*/
class MessageComponentInteraction extends BaseInteraction {
readonly type: InteractionType.MessageComponent;
readonly customId: string;
readonly componentType: ComponentType;
readonly message: Message;
readonly component: MessageActionRowComponent;
// Response methods (inherited from RepliableInteraction)
reply(options: InteractionReplyOptions): Promise<InteractionResponse>;
update(options: InteractionUpdateOptions): Promise<InteractionResponse>;
deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse>;
followUp(options: InteractionReplyOptions): Promise<Message>;
// Utility methods
inGuild(): this is MessageComponentInteraction & { guildId: Snowflake; guild: Guild; member: GuildMember };
}
interface InteractionUpdateOptions extends BaseMessageOptions {
fetchReply?: boolean;
}
interface InteractionDeferUpdateOptions {
fetchReply?: boolean;
}Handle various types of select menu interactions.
/**
* Base class for select menu interactions
* @extends MessageComponentInteraction
*/
class SelectMenuInteraction extends MessageComponentInteraction {
readonly values: string[];
readonly component: BaseSelectMenuComponent;
}
/**
* String select menu interaction
* @extends SelectMenuInteraction
*/
class StringSelectMenuInteraction extends SelectMenuInteraction {
readonly componentType: ComponentType.StringSelect;
readonly component: StringSelectMenuComponent;
}
/**
* User select menu interaction
* @extends SelectMenuInteraction
*/
class UserSelectMenuInteraction extends SelectMenuInteraction {
readonly componentType: ComponentType.UserSelect;
readonly component: UserSelectMenuComponent;
readonly users: Collection<Snowflake, User>;
readonly members: Collection<Snowflake, GuildMember>;
}
/**
* Role select menu interaction
* @extends SelectMenuInteraction
*/
class RoleSelectMenuInteraction extends SelectMenuInteraction {
readonly componentType: ComponentType.RoleSelect;
readonly component: RoleSelectMenuComponent;
readonly roles: Collection<Snowflake, Role>;
}
/**
* Channel select menu interaction
* @extends SelectMenuInteraction
*/
class ChannelSelectMenuInteraction extends SelectMenuInteraction {
readonly componentType: ComponentType.ChannelSelect;
readonly component: ChannelSelectMenuComponent;
readonly channels: Collection<Snowflake, APIInteractionDataResolvedChannel | GuildChannel | ThreadChannel>;
}
/**
* Mentionable select menu interaction
* @extends SelectMenuInteraction
*/
class MentionableSelectMenuInteraction extends SelectMenuInteraction {
readonly componentType: ComponentType.MentionableSelect;
readonly component: MentionableSelectMenuComponent;
readonly users: Collection<Snowflake, User>;
readonly members: Collection<Snowflake, GuildMember>;
readonly roles: Collection<Snowflake, Role>;
}Handle modal form submissions with input validation.
/**
* Represents a modal submit interaction
* @extends BaseInteraction
*/
class ModalSubmitInteraction extends BaseInteraction {
readonly type: InteractionType.ModalSubmit;
readonly customId: string;
readonly fields: ModalSubmitFields;
readonly components: ActionRow<ModalActionRowComponent>[];
readonly message: Message | null;
// Response methods (inherited from RepliableInteraction)
reply(options: InteractionReplyOptions): Promise<InteractionResponse>;
update(options: InteractionUpdateOptions): Promise<InteractionResponse>;
deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse>;
deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse>;
followUp(options: InteractionReplyOptions): Promise<Message>;
}
/**
* Handles modal form field values
*/
class ModalSubmitFields {
constructor(components: ModalActionRowComponent[][], interaction: ModalSubmitInteraction);
getTextInputValue(customId: string): string;
getField(customId: string, type: ComponentType): ModalActionRowComponent;
getFields(customId?: string, type?: ComponentType): ModalActionRowComponent[];
}Usage Examples:
// Handle button interactions
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isButton()) return;
if (interaction.customId === 'confirm_action') {
await interaction.update({
content: 'Action confirmed!',
components: [] // Remove buttons
});
}
if (interaction.customId === 'show_modal') {
const modal = new ModalBuilder()
.setCustomId('feedback_modal')
.setTitle('Feedback Form')
.addComponents(
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setCustomId('feedback_input')
.setLabel('Your feedback')
.setStyle(TextInputStyle.Paragraph)
.setPlaceholder('Tell us what you think...')
.setRequired(true)
)
);
await interaction.showModal(modal);
}
});
// Handle select menu interactions
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isAnySelectMenu()) return;
if (interaction.customId === 'role_select') {
if (interaction.isRoleSelectMenu()) {
const selectedRoles = interaction.roles;
await interaction.reply({
content: `You selected: ${selectedRoles.map(role => role.name).join(', ')}`,
ephemeral: true
});
}
}
});
// Handle modal submissions
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isModalSubmit()) return;
if (interaction.customId === 'feedback_modal') {
const feedback = interaction.fields.getTextInputValue('feedback_input');
await interaction.reply({
content: `Thank you for your feedback: ${feedback}`,
ephemeral: true
});
}
});Create, update, and manage application commands.
/**
* Represents an application command
*/
class ApplicationCommand extends Base {
readonly id: Snowflake;
readonly applicationId: Snowflake;
readonly guildId: Snowflake | null;
readonly guild: Guild | null;
readonly name: string;
readonly nameLocalizations: LocalizationMap | null;
readonly description: string;
readonly descriptionLocalizations: LocalizationMap | null;
readonly type: ApplicationCommandType;
readonly options: ApplicationCommandOption[];
readonly defaultMemberPermissions: Readonly<PermissionsBitField> | null;
readonly dmPermission: boolean | null;
readonly nsfw: boolean;
readonly version: Snowflake;
// Command management
edit(options: ApplicationCommandEditOptions): Promise<ApplicationCommand>;
delete(): Promise<ApplicationCommand>;
setName(name: string): Promise<ApplicationCommand>;
setDescription(description: string): Promise<ApplicationCommand>;
setDefaultMemberPermissions(defaultMemberPermissions: PermissionResolvable | null): Promise<ApplicationCommand>;
setDMPermission(dmPermission?: boolean): Promise<ApplicationCommand>;
}
/**
* Manages application commands for a client
*/
class ApplicationCommandManager extends CachedManager<Snowflake, ApplicationCommand, ApplicationCommandResolvable> {
create(command: ApplicationCommandData): Promise<ApplicationCommand>;
edit(command: ApplicationCommandResolvable, data: ApplicationCommandEditOptions): Promise<ApplicationCommand>;
delete(command: ApplicationCommandResolvable): Promise<ApplicationCommand | null>;
set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, ApplicationCommand>>;
}
/**
* Manages application commands for a guild
*/
class GuildApplicationCommandManager extends ApplicationCommandManager {
readonly guild: Guild;
readonly permissions: GuildApplicationCommandPermissionsManager;
create(command: ApplicationCommandData): Promise<ApplicationCommand>;
set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, ApplicationCommand>>;
}
interface ApplicationCommandData {
name: string;
nameLocalizations?: LocalizationMap;
description: string;
descriptionLocalizations?: LocalizationMap;
type?: ApplicationCommandType;
options?: ApplicationCommandOptionData[];
defaultMemberPermissions?: PermissionResolvable | null;
dmPermission?: boolean;
nsfw?: boolean;
}Advanced interaction response handling and management.
/**
* Represents an interaction response
*/
class InteractionResponse {
constructor(interaction: BaseInteraction, id?: Snowflake);
readonly interaction: BaseInteraction;
readonly id: Snowflake | null;
// Response management
edit(options: InteractionEditReplyOptions): Promise<Message>;
delete(): Promise<void>;
fetch(): Promise<Message>;
}
/**
* Interaction webhook for advanced response handling
*/
class InteractionWebhook extends PartialWebhookMixin() {
constructor(client: Client, id: Snowflake, token: string);
readonly token: string;
readonly client: Client;
editMessage(message: MessageResolvable | '@original', options: InteractionEditReplyOptions): Promise<Message>;
fetchMessage(message: Snowflake | '@original'): Promise<Message>;
deleteMessage(message: MessageResolvable | '@original'): Promise<void>;
}Usage Examples:
// Register commands with different types
const commands = [
// Slash command with options
{
name: 'ban',
description: 'Ban a user from the server',
type: ApplicationCommandType.ChatInput,
options: [
{
name: 'user',
description: 'User to ban',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'reason',
description: 'Reason for ban',
type: ApplicationCommandOptionType.String,
required: false
}
],
defaultMemberPermissions: PermissionFlagsBits.BanMembers
},
// User context menu command
{
name: 'Get User Info',
type: ApplicationCommandType.User
},
// Message context menu command
{
name: 'Report Message',
type: ApplicationCommandType.Message
}
];
// Set commands globally
await client.application?.commands.set(commands);
// Set commands for specific guild
await guild.commands.set(commands);
// Advanced interaction handling with error management
client.on(Events.InteractionCreate, async interaction => {
try {
if (interaction.isChatInputCommand()) {
await handleSlashCommand(interaction);
} else if (interaction.isButton()) {
await handleButtonInteraction(interaction);
} else if (interaction.isModalSubmit()) {
await handleModalSubmit(interaction);
}
} catch (error) {
console.error('Interaction error:', error);
const errorMessage = {
content: 'There was an error while executing this interaction!',
ephemeral: true
};
if (interaction.replied || interaction.deferred) {
await interaction.followUp(errorMessage);
} else {
await interaction.reply(errorMessage);
}
}
});