fix(bot)!: Split DiscordSelectComponent into specific select components (#4690)

* refactor(bot)!: setup desired properties for all transformers

SetupDesiredProps when is given an object that does not corrispond to a transformer object that supports desired properties will behave like TransformProperty on the entire object as when it tries to get the properties for said object it will find `never` as the props and for `IsKeyDesired` a props of `never` means that all props are desired.

* Use Equals helper, clean up a bit the code

* Explicit the IsKeyDesired TProps never behavior

* fix(bot): Bug with return type in functions

* fix(bot)!: Split DiscordSelectComponent into specific select components

And add missing resolved property from the responses, since this now correctly transformers the responses, resolved has to be added.
The reverse transformer does not transform resolved as it requires a bunch of others, such as a user, role, message reverse transformers etc.

* Apply suggestions from code review

Co-authored-by: Awesome Stickz <awesome@stickz.dev>
This commit is contained in:
Fleny
2026-02-16 19:07:57 +01:00
committed by GitHub
parent 8939cc8492
commit 3e35160504
6 changed files with 455 additions and 59 deletions

View File

@@ -354,6 +354,7 @@ export function createDesiredPropertiesObject<T extends RecursivePartial<Transfo
size: defaultValue,
component: defaultValue,
values: defaultValue,
resolved: defaultValue,
...desiredProperties.component,
},
forumTag: {

View File

@@ -1,6 +1,8 @@
import {
type DiscordActionRow,
type DiscordButtonComponent,
type DiscordChannelSelectComponent,
type DiscordChannelSelectInteractionResponseFromModal,
type DiscordContainerComponent,
type DiscordFileComponent,
type DiscordFileUploadComponent,
@@ -9,18 +11,24 @@ import {
type DiscordLabelInteractionResponse,
type DiscordMediaGalleryComponent,
type DiscordMediaGalleryItem,
type DiscordMentionableSelectComponent,
type DiscordMentionableSelectInteractionResponseFromModal,
type DiscordMessageComponent,
type DiscordMessageComponentFromModalInteractionResponse,
type DiscordRoleSelectComponent,
type DiscordRoleSelectInteractionResponseFromModal,
type DiscordSectionComponent,
type DiscordSelectMenuComponent,
type DiscordSeparatorComponent,
type DiscordStringSelectInteractionResponse,
type DiscordStringSelectComponent,
type DiscordStringSelectInteractionResponseFromModal,
type DiscordTextDisplayComponent,
type DiscordTextDisplayInteractionResponse,
type DiscordTextInputComponent,
type DiscordTextInputInteractionResponse,
type DiscordThumbnailComponent,
type DiscordUnfurledMediaItem,
type DiscordUserSelectComponent,
type DiscordUserSelectInteractionResponseFromModal,
MessageComponentTypes,
} from '@discordeno/types';
import type { Bot } from '../bot.js';
@@ -45,11 +53,19 @@ export function transformComponent(bot: Bot, payload: DiscordMessageComponent |
component = transformInputTextComponent(bot, payload);
break;
case MessageComponentTypes.StringSelect:
component = transformStringSelectMenuComponent(bot, payload);
break;
case MessageComponentTypes.UserSelect:
component = transformUserSelectMenuComponent(bot, payload);
break;
case MessageComponentTypes.RoleSelect:
component = transformRoleSelectMenuComponent(bot, payload);
break;
case MessageComponentTypes.MentionableSelect:
component = transformMentionableSelectMenuComponent(bot, payload);
break;
case MessageComponentTypes.ChannelSelect:
component = transformSelectMenuComponent(bot, payload);
component = transformChannelSelectMenuComponent(bot, payload);
break;
case MessageComponentTypes.Section:
component = transformSectionComponent(bot, payload);
@@ -170,7 +186,7 @@ function transformInputTextComponent(bot: Bot, payload: DiscordTextInputComponen
return input;
}
function transformSelectMenuComponent(bot: Bot, payload: DiscordSelectMenuComponent | DiscordStringSelectInteractionResponse) {
function transformStringSelectMenuComponent(bot: Bot, payload: DiscordStringSelectComponent | DiscordStringSelectInteractionResponseFromModal) {
const props = bot.transformers.desiredProperties.component;
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
@@ -185,12 +201,6 @@ function transformSelectMenuComponent(bot: Bot, payload: DiscordSelectMenuCompon
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
if (props.defaultValues && payload.default_values)
select.defaultValues = payload.default_values.map((defaultValue) => ({
id: bot.transformers.snowflake(defaultValue.id),
type: defaultValue.type,
}));
if (props.channelTypes && payload.channel_types) select.channelTypes = payload.channel_types;
if (props.options && payload.options)
select.options = payload.options.map((option) => ({
label: option.label,
@@ -211,6 +221,118 @@ function transformSelectMenuComponent(bot: Bot, payload: DiscordSelectMenuCompon
return select;
}
function transformUserSelectMenuComponent(bot: Bot, payload: DiscordUserSelectComponent | DiscordUserSelectInteractionResponseFromModal) {
const props = bot.transformers.desiredProperties.component;
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
if (props.type && payload.type) select.type = payload.type;
if (props.id && payload.id) select.id = payload.id;
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
// Check if this is the user select response
if ('values' in payload) {
if (props.values && payload.values) select.values = payload.values;
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
} else {
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
if (props.defaultValues && payload.default_values)
select.defaultValues = payload.default_values.map((defaultValue) => ({
id: bot.transformers.snowflake(defaultValue.id),
type: defaultValue.type,
}));
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
}
return select;
}
function transformRoleSelectMenuComponent(bot: Bot, payload: DiscordRoleSelectComponent | DiscordRoleSelectInteractionResponseFromModal) {
const props = bot.transformers.desiredProperties.component;
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
if (props.type && payload.type) select.type = payload.type;
if (props.id && payload.id) select.id = payload.id;
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
// Check if this is the role select response
if ('values' in payload) {
if (props.values && payload.values) select.values = payload.values;
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
} else {
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
if (props.defaultValues && payload.default_values)
select.defaultValues = payload.default_values.map((defaultValue) => ({
id: bot.transformers.snowflake(defaultValue.id),
type: defaultValue.type,
}));
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
}
return select;
}
function transformMentionableSelectMenuComponent(
bot: Bot,
payload: DiscordMentionableSelectComponent | DiscordMentionableSelectInteractionResponseFromModal,
) {
const props = bot.transformers.desiredProperties.component;
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
if (props.type && payload.type) select.type = payload.type;
if (props.id && payload.id) select.id = payload.id;
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
// Check if this is the mentionable select response
if ('values' in payload) {
if (props.values && payload.values) select.values = payload.values;
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
} else {
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
if (props.defaultValues && payload.default_values)
select.defaultValues = payload.default_values.map((defaultValue) => ({
id: bot.transformers.snowflake(defaultValue.id),
type: defaultValue.type,
}));
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
}
return select;
}
function transformChannelSelectMenuComponent(bot: Bot, payload: DiscordChannelSelectComponent | DiscordChannelSelectInteractionResponseFromModal) {
const props = bot.transformers.desiredProperties.component;
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
if (props.type && payload.type) select.type = payload.type;
if (props.id && payload.id) select.id = payload.id;
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
// Check if this is the channel select response
if ('values' in payload) {
if (props.values && payload.values) select.values = payload.values;
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
} else {
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
if (props.defaultValues && payload.default_values)
select.defaultValues = payload.default_values.map((defaultValue) => ({
id: bot.transformers.snowflake(defaultValue.id),
type: defaultValue.type,
}));
if (props.channelTypes && payload.channel_types) select.channelTypes = payload.channel_types;
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
}
return select;
}
function transformSectionComponent(bot: Bot, payload: DiscordSectionComponent) {
const props = bot.transformers.desiredProperties.component;
const section = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
@@ -303,9 +425,9 @@ function transformLabelComponent(bot: Bot, payload: DiscordLabelComponent | Disc
return label;
}
function transformFileUploadComponent(bot: Bot, payload: DiscordFileUploadComponent | DiscordFileUploadInteractionResponse): Component {
function transformFileUploadComponent(bot: Bot, payload: DiscordFileUploadComponent | DiscordFileUploadInteractionResponse) {
const props = bot.transformers.desiredProperties.component;
const fileUpload = {} as Component;
const fileUpload = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
if (props.type && payload.type) fileUpload.type = payload.type;
if (props.id && payload.id) fileUpload.id = payload.id;

View File

@@ -2,22 +2,30 @@ import {
type ButtonStyles,
type DiscordActionRow,
type DiscordButtonComponent,
type DiscordChannelSelectComponent,
type DiscordChannelSelectInteractionResponseFromModal,
type DiscordContainerComponent,
type DiscordFileComponent,
type DiscordFileUploadComponent,
type DiscordLabelComponent,
type DiscordMediaGalleryComponent,
type DiscordMediaGalleryItem,
type DiscordMentionableSelectComponent,
type DiscordMentionableSelectInteractionResponseFromModal,
type DiscordMessageComponent,
type DiscordMessageComponentFromModalInteractionResponse,
type DiscordRoleSelectComponent,
type DiscordRoleSelectInteractionResponseFromModal,
type DiscordSectionComponent,
type DiscordSelectMenuComponent,
type DiscordStringSelectComponent,
type DiscordStringSelectInteractionResponseFromModal,
type DiscordTextDisplayComponent,
type DiscordTextInputComponent,
type DiscordTextInputInteractionResponse,
type DiscordThumbnailComponent,
type DiscordUnfurledMediaItem,
type DiscordUserSelectComponent,
type DiscordUserSelectInteractionResponseFromModal,
MessageComponentTypes,
type TextStyles,
} from '@discordeno/types';
@@ -39,11 +47,15 @@ export function transformComponentToDiscordComponent(
case MessageComponentTypes.TextInput:
return transformInputTextComponent(bot, payload);
case MessageComponentTypes.StringSelect:
case MessageComponentTypes.ChannelSelect:
case MessageComponentTypes.RoleSelect:
return transformStringSelectMenuComponent(bot, payload);
case MessageComponentTypes.UserSelect:
return transformUserSelectMenuComponent(bot, payload);
case MessageComponentTypes.RoleSelect:
return transformRoleSelectMenuComponent(bot, payload);
case MessageComponentTypes.MentionableSelect:
return transformSelectMenuComponent(bot, payload);
return transformMentionableSelectMenuComponent(bot, payload);
case MessageComponentTypes.ChannelSelect:
return transformChannelSelectMenuComponent(bot, payload);
case MessageComponentTypes.Section:
return transformSectionComponent(bot, payload);
case MessageComponentTypes.File:
@@ -139,25 +151,23 @@ function transformInputTextComponent(_bot: Bot, payload: Component): DiscordText
};
}
function transformSelectMenuComponent(bot: Bot, payload: Component): DiscordSelectMenuComponent | DiscordStringSelectInteractionResponseFromModal {
function transformStringSelectMenuComponent(
bot: Bot,
payload: Component,
): DiscordStringSelectComponent | DiscordStringSelectInteractionResponseFromModal {
if (payload.values) {
return {
type: MessageComponentTypes.StringSelect,
values: payload.values,
custom_id: payload.customId!,
id: payload.id!,
};
} satisfies DiscordStringSelectInteractionResponseFromModal;
}
return {
type: payload.type as DiscordSelectMenuComponent['type'],
type: MessageComponentTypes.StringSelect,
id: payload.id,
custom_id: payload.customId!,
channel_types: payload.channelTypes,
default_values: payload.defaultValues?.map((defaultValue) => ({
id: bot.transformers.reverse.snowflake(defaultValue.id),
type: defaultValue.type,
})),
disabled: payload.disabled,
max_values: payload.maxValues,
min_values: payload.minValues,
@@ -173,10 +183,117 @@ function transformSelectMenuComponent(bot: Bot, payload: Component): DiscordSele
}
: undefined,
default: option.default,
})),
}))!,
placeholder: payload.placeholder,
required: payload.required,
};
} satisfies DiscordStringSelectComponent;
}
function transformUserSelectMenuComponent(bot: Bot, payload: Component): DiscordUserSelectComponent | DiscordUserSelectInteractionResponseFromModal {
if (payload.values) {
return {
type: MessageComponentTypes.UserSelect,
values: payload.values,
custom_id: payload.customId!,
id: payload.id!,
// TODO: Add resolved reverse transformer
resolved: {},
} satisfies DiscordUserSelectInteractionResponseFromModal;
}
return {
type: MessageComponentTypes.UserSelect,
id: payload.id,
custom_id: payload.customId!,
disabled: payload.disabled,
max_values: payload.maxValues,
min_values: payload.minValues,
placeholder: payload.placeholder,
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
required: payload.required,
} satisfies DiscordUserSelectComponent;
}
function transformRoleSelectMenuComponent(bot: Bot, payload: Component): DiscordRoleSelectComponent | DiscordRoleSelectInteractionResponseFromModal {
if (payload.values) {
return {
type: MessageComponentTypes.RoleSelect,
values: payload.values,
custom_id: payload.customId!,
id: payload.id!,
// TODO: Add resolved reverse transformer
resolved: {},
} satisfies DiscordRoleSelectInteractionResponseFromModal;
}
return {
type: MessageComponentTypes.RoleSelect,
id: payload.id,
custom_id: payload.customId!,
disabled: payload.disabled,
max_values: payload.maxValues,
min_values: payload.minValues,
placeholder: payload.placeholder,
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
required: payload.required,
} satisfies DiscordRoleSelectComponent;
}
function transformMentionableSelectMenuComponent(
bot: Bot,
payload: Component,
): DiscordMentionableSelectComponent | DiscordMentionableSelectInteractionResponseFromModal {
if (payload.values) {
return {
type: MessageComponentTypes.MentionableSelect,
values: payload.values,
custom_id: payload.customId!,
id: payload.id!,
// TODO: Add resolved reverse transformer
resolved: {},
} satisfies DiscordMentionableSelectInteractionResponseFromModal;
}
return {
type: MessageComponentTypes.MentionableSelect,
id: payload.id,
custom_id: payload.customId!,
disabled: payload.disabled,
max_values: payload.maxValues,
min_values: payload.minValues,
placeholder: payload.placeholder,
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
required: payload.required,
} satisfies DiscordMentionableSelectComponent;
}
function transformChannelSelectMenuComponent(
bot: Bot,
payload: Component,
): DiscordChannelSelectComponent | DiscordChannelSelectInteractionResponseFromModal {
if (payload.values) {
return {
type: MessageComponentTypes.ChannelSelect,
values: payload.values,
custom_id: payload.customId!,
id: payload.id!,
// TODO: Add resolved reverse transformer
resolved: {},
} satisfies DiscordChannelSelectInteractionResponseFromModal;
}
return {
type: MessageComponentTypes.ChannelSelect,
id: payload.id,
custom_id: payload.customId!,
disabled: payload.disabled,
max_values: payload.maxValues,
min_values: payload.minValues,
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
placeholder: payload.placeholder,
required: payload.required,
channel_types: payload.channelTypes,
} satisfies DiscordChannelSelectComponent;
}
function transformSectionComponent(bot: Bot, payload: Component): DiscordSectionComponent {

View File

@@ -599,7 +599,7 @@ export interface Component {
/** a list of child components */
components?: Component[];
/** List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values */
defaultValues?: DiscordComponentDefaultValue[];
defaultValues?: ComponentDefaultValue[];
/** Identifier for a purchasable SKU, only available when using premium-style buttons */
skuId?: bigint;
/** Optional identifier for component */
@@ -632,6 +632,8 @@ export interface Component {
component?: Component;
/** The text of the selected options */
values?: string[];
/** Resolved entities from selected options */
resolved?: InteractionDataResolved;
}
export interface UnfurledMediaItem {
@@ -658,7 +660,7 @@ export interface MediaGalleryItem {
spoiler?: boolean;
}
export interface DiscordComponentDefaultValue {
export interface ComponentDefaultValue {
/** ID of a user, role, or channel */
id: bigint;
/** Type of value that id represents. */

View File

@@ -46,7 +46,11 @@ export enum MessageComponentTypes {
export type DiscordMessageComponents = DiscordMessageComponent[];
export type DiscordMessageComponent =
| DiscordActionRow
| DiscordSelectMenuComponent
| DiscordStringSelectComponent
| DiscordUserSelectComponent
| DiscordRoleSelectComponent
| DiscordMentionableSelectComponent
| DiscordChannelSelectComponent
| DiscordButtonComponent
| DiscordTextInputComponent
| DiscordSectionComponent
@@ -62,7 +66,12 @@ export type DiscordMessageComponent =
export type DiscordMessageComponentFromModalInteractionResponse =
| DiscordTextInputInteractionResponse
| DiscordTextDisplayInteractionResponse
| DiscordLabelInteractionResponse;
| DiscordLabelInteractionResponse
| DiscordRoleSelectInteractionResponseFromModal
| DiscordUserSelectInteractionResponseFromModal
| DiscordStringSelectInteractionResponseFromModal
| DiscordChannelSelectInteractionResponseFromModal
| DiscordMentionableSelectInteractionResponseFromModal;
export type DiscordMessageComponentFromMessageComponentInteractionResponse =
| DiscordRoleSelectInteractionResponseFromMessageComponent
@@ -92,7 +101,15 @@ export interface DiscordActionRow extends DiscordBaseComponent {
* Using a {@link DiscordTextInputComponent} inside the Action Row is deprecated,
* use a {@link DiscordLabelComponent} for modals
*/
components: (DiscordButtonComponent | DiscordSelectMenuComponent | DiscordTextInputComponent)[];
components: (
| DiscordButtonComponent
| DiscordStringSelectComponent
| DiscordUserSelectComponent
| DiscordRoleSelectComponent
| DiscordMentionableSelectComponent
| DiscordChannelSelectComponent
| DiscordTextInputComponent
)[];
}
/** https://docs.discord.com/developers/components/reference#button-button-structure */
@@ -159,25 +176,14 @@ export enum ButtonStyles {
Premium,
}
/**
* https://docs.discord.com/developers/components/reference#string-select
* https://docs.discord.com/developers/components/reference#user-select
* https://docs.discord.com/developers/components/reference#role-select
* https://docs.discord.com/developers/components/reference#mentionable-select
* https://docs.discord.com/developers/components/reference#channel-select
*/
export interface DiscordSelectMenuComponent extends DiscordBaseComponent {
type:
| MessageComponentTypes.StringSelect
| MessageComponentTypes.UserSelect
| MessageComponentTypes.RoleSelect
| MessageComponentTypes.MentionableSelect
| MessageComponentTypes.ChannelSelect;
/** https://docs.discord.com/developers/components/reference#string-select-string-select-structure */
export interface DiscordStringSelectComponent extends DiscordBaseComponent {
type: MessageComponentTypes.StringSelect;
/** A custom identifier for this component. Maximum 100 characters. */
custom_id: string;
/** Specified choices in a select menu; Maximum of 25 items. */
options?: DiscordSelectOption[];
/** The choices! Maximum of 25 items. */
options: DiscordSelectOption[];
/** A custom placeholder text if nothing is selected. Maximum 150 characters. */
placeholder?: string;
/** The minimum number of items that must be selected. Default 1. Between 0-25. */
@@ -188,7 +194,7 @@ export interface DiscordSelectMenuComponent extends DiscordBaseComponent {
* Whether this component is required to be filled
*
* @remarks
* This value is only valid for select menus in modals
* This value is only valid for string select menus in modals
*
* @default true
*/
@@ -202,15 +208,6 @@ export interface DiscordSelectMenuComponent extends DiscordBaseComponent {
* @default false
*/
disabled?: boolean;
/**
* List of default values for auto-populated select menu components
*
* @remarks
* The number of default values must be in the range defined by min_values and max_values
*/
default_values?: DiscordSelectMenuDefaultValue[];
/** List of channel types to include in a channel select menu options list */
channel_types?: ChannelTypes[];
}
/** https://docs.discord.com/developers/components/reference#string-select-select-option-structure */
@@ -303,6 +300,43 @@ export interface DiscordTextInputInteractionResponse {
value: string;
}
/** https://docs.discord.com/developers/components/reference#user-select-user-select-structure */
export interface DiscordUserSelectComponent extends DiscordBaseComponent {
type: MessageComponentTypes.UserSelect;
/** A custom identifier for this component. Maximum 100 characters. */
custom_id: string;
/** A custom placeholder text if nothing is selected. Maximum 150 characters. */
placeholder?: string;
/**
* List of default values for auto-populated select menu components
* The number of default values must be in the range defined by minValues and maxValues
*/
default_values?: DiscordSelectMenuDefaultValue[];
/** The minimum number of items that must be selected. Default 1. Between 0-25. */
min_values?: number;
/** The maximum number of items that can be selected. Default 1. Max 25. */
max_values?: number;
/**
* Whether this component is required to be filled
*
* @remarks
* This value is only valid for string select menus in modals
*
* @default true
*/
required?: boolean;
/**
* Whether select menu is disabled
*
* @remarks
* This value cannot be set for select menus in modals
*
* @default false
*/
disabled?: boolean;
}
/** https://docs.discord.com/developers/components/reference#user-select-select-default-value-structure */
export interface DiscordSelectMenuDefaultValue {
/** ID of a user, role, or channel */
@@ -338,6 +372,43 @@ export type DiscordUserSelectInteractionResponseFromModal = Require<Omit<Discord
/** https://docs.discord.com/developers/components/reference#user-select-user-select-interaction-response-structure */
export type DiscordUserSelectInteractionResponseFromMessageComponent = Require<Omit<DiscordUserSelectInteractionResponse, 'type'>, 'component_type'>;
/** https://docs.discord.com/developers/components/reference#role-select-role-select-structure */
export interface DiscordRoleSelectComponent extends DiscordBaseComponent {
type: MessageComponentTypes.RoleSelect;
/** A custom identifier for this component. Maximum 100 characters. */
custom_id: string;
/** A custom placeholder text if nothing is selected. Maximum 150 characters. */
placeholder?: string;
/**
* List of default values for auto-populated select menu components
* The number of default values must be in the range defined by minValues and maxValues
*/
default_values?: DiscordSelectMenuDefaultValue[];
/** The minimum number of items that must be selected. Default 1. Between 0-25. */
min_values?: number;
/** The maximum number of items that can be selected. Default 1. Max 25. */
max_values?: number;
/**
* Whether this component is required to be filled
*
* @remarks
* This value is only valid for string select menus in modals
*
* @default true
*/
required?: boolean;
/**
* Whether select menu is disabled
*
* @remarks
* This value cannot be set for select menus in modals
*
* @default false
*/
disabled?: boolean;
}
/** https://docs.discord.com/developers/components/reference#role-select-role-select-interaction-response-structure */
export interface DiscordRoleSelectInteractionResponse {
/**
@@ -365,6 +436,43 @@ export type DiscordRoleSelectInteractionResponseFromModal = Require<Omit<Discord
/** https://docs.discord.com/developers/components/reference#role-select-role-select-interaction-response-structure */
export type DiscordRoleSelectInteractionResponseFromMessageComponent = Require<Omit<DiscordRoleSelectInteractionResponse, 'type'>, 'component_type'>;
/** https://docs.discord.com/developers/components/reference#mentionable-select-mentionable-select-structure */
export interface DiscordMentionableSelectComponent extends DiscordBaseComponent {
type: MessageComponentTypes.MentionableSelect;
/** A custom identifier for this component. Maximum 100 characters. */
custom_id: string;
/** A custom placeholder text if nothing is selected. Maximum 150 characters. */
placeholder?: string;
/**
* List of default values for auto-populated select menu components
* The number of default values must be in the range defined by minValues and maxValues
*/
default_values?: DiscordSelectMenuDefaultValue[];
/** The minimum number of items that must be selected. Default 1. Between 0-25. */
min_values?: number;
/** The maximum number of items that can be selected. Default 1. Max 25. */
max_values?: number;
/**
* Whether this component is required to be filled
*
* @remarks
* This value is only valid for string select menus in modals
*
* @default true
*/
required?: boolean;
/**
* Whether select menu is disabled
*
* @remarks
* This value cannot be set for select menus in modals
*
* @default false
*/
disabled?: boolean;
}
/** https://docs.discord.com/developers/components/reference#mentionable-select-mentionable-select-interaction-response-structure */
export interface DiscordMentionableSelectInteractionResponse {
/**
@@ -398,6 +506,45 @@ export type DiscordMentionableSelectInteractionResponseFromMessageComponent = Re
'component_type'
>;
/** https://docs.discord.com/developers/components/reference#channel-select-channel-select-structure */
export interface DiscordChannelSelectComponent extends DiscordBaseComponent {
type: MessageComponentTypes.ChannelSelect;
/** A custom identifier for this component. Maximum 100 characters. */
custom_id: string;
/** List of channel types to include in the options list */
channel_types?: ChannelTypes[];
/** A custom placeholder text if nothing is selected. Maximum 150 characters. */
placeholder?: string;
/**
* List of default values for auto-populated select menu components
* The number of default values must be in the range defined by minValues and maxValues
*/
default_values?: DiscordSelectMenuDefaultValue[];
/** The minimum number of items that must be selected. Default 1. Between 0-25. */
min_values?: number;
/** The maximum number of items that can be selected. Default 1. Max 25. */
max_values?: number;
/**
* Whether this component is required to be filled
*
* @remarks
* This value is only valid for string select menus in modals
*
* @default true
*/
required?: boolean;
/**
* Whether select menu is disabled
*
* @remarks
* This value cannot be set for select menus in modals
*
* @default false
*/
disabled?: boolean;
}
/** https://docs.discord.com/developers/components/reference#channel-select-channel-select-interaction-response-structure */
export interface DiscordChannelSelectInteractionResponse {
/**
@@ -550,7 +697,14 @@ export interface DiscordLabelComponent extends DiscordBaseComponent {
*/
description?: string;
/** The component within the label */
component: DiscordTextInputComponent | DiscordSelectMenuComponent | DiscordFileUploadComponent;
component:
| DiscordTextInputComponent
| DiscordStringSelectComponent
| DiscordUserSelectComponent
| DiscordRoleSelectComponent
| DiscordMentionableSelectComponent
| DiscordChannelSelectComponent
| DiscordFileUploadComponent;
}
/** https://docs.discord.com/developers/components/reference#label-label-interaction-response-structure */

View File

@@ -171,7 +171,7 @@ export interface DiscordInteractionDataResolved {
/** The Ids and Message objects */
messages?: Record<string, Partial<DiscordMessage>>;
/** The ids and attachment objects */
attachments: Record<string, DiscordAttachment>;
attachments?: Record<string, DiscordAttachment>;
}
/** https://docs.discord.com/developers/interactions/receiving-and-responding#interaction-object-application-command-interaction-data-option-structure */