import { type AutocompleteInteraction, type User, type Attachment, type Role, type GuildBasedChannel, type ApplicationCommandOptionChoiceData, } from "discord.js"; export const OPTION_TYPES = { subcommand: 1, subcommandGroup: 2, string: 3, integer: 4, boolean: 5, user: 6, channel: 7, role: 8, mentionable: 9, number: 10, attachment: 11, } as const; type OptionType = keyof typeof OPTION_TYPES; export interface Option { type: OptionType; description?: string; required: Req; autocomplete?: ( interaction: AutocompleteInteraction, value: T, ) => Promise | ApplicationCommandOptionChoiceData[]; __type?: T; } export interface CommandOption extends Option { description: string; } export type InferOptions = { [K in keyof O]: O[K] extends Option ? Required extends true ? Type : Type | undefined : never; }; export type AutocompleteFn = ( interaction: AutocompleteInteraction, value: T, ) => Promise | ApplicationCommandOptionChoiceData[]; const createOption = (type: OptionType) => { return (( descriptionOrConfig?: string | { required?: boolean; autocomplete?: AutocompleteFn }, config?: { required?: boolean; autocomplete?: AutocompleteFn }, ): Option => { const hasDescription = typeof descriptionOrConfig === "string"; const description = hasDescription ? descriptionOrConfig : undefined; const actualConfig = hasDescription ? config : descriptionOrConfig; return { type, description, required: actualConfig?.required ?? false, autocomplete: actualConfig?.autocomplete, }; }) as { // w/ description for commands ( description: string, config: { required: Req; autocomplete?: AutocompleteFn }, ): CommandOption; ( description: string, config?: { required?: false; autocomplete?: AutocompleteFn }, ): CommandOption; // w/out description for components (config: { required: Req; autocomplete?: AutocompleteFn; }): Option; (config?: { required?: false; autocomplete?: AutocompleteFn }): Option; }; }; export const option = { string: createOption("string"), integer: createOption("integer"), number: createOption("number"), boolean: createOption("boolean"), user: createOption("user"), channel: createOption("channel"), role: createOption("role"), mentionable: createOption("mentionable"), attachment: createOption("attachment"), };