discord.js - Hantera Message- och CommandInteraction-typer i Discord-skråkommandon med TypeScript
Jag har en Discord-bot med ett ganska stort antal kommandon. Den växte långsamt från en mycket liten kodbas i Java och har över åren utvecklats till ett ganska okej Typescript/discord.js-projekt. Men det blev aldrig aktuellt att konvertera kommandona till de inte-så-nya-längre slash-kommandon som Discord släppte. Dels för att det helt enkelt inte passar botens tema. Men nu finns det ett par kommandon som har en mycket svårfångad syntax, så jag bestämde mig för att också ge dem ett slash-kommando. Men när jag försökte utöka min typ för kommandona stoppade det upp.
Här är några viktiga rader från min types.ts-fil:
type RunFunction = (message: Message, arg: string) => Awaitable<string | MessagePayload | MessageCreateOptions | void>;
type Command = {
run: string | RunFunction
}
type Module = {
commands?: Record<string, RunFunction | Command | string>
}
För närvarande har jag ett par TypeScript-filer i en mapp som heter modules, där varje fil exporterar ett Module-objekt. Kommandona indexeras efter deras namn i commands-objektet och värdet kan antingen vara bara en sträng med det bokstavliga svaret som boten kommer att skicka tillbaka, RunFunction som körs när kommandot anropas, eller det kan vara ett Command-objekt som specificerar ett par icke-obligatoriska fält och en egenskap run som borde vara tydlig vad den gör.
Problemet är att RunFunction tar ett Message-objekt som parameter, vilket inte existerar när man hanterar interaktioner.
Min första tanke var att inkludera en annan egenskap i Command kallad acceptsInteraction som skulle tala om för TypeScript att run är en funktion som accepterar båda typerna på detta sätt:
type Command = {
acceptsInteraction: true;
run: (interactionOrMessage: CommandInteraction | Message, arguments?: string) => Awaitable<string | MessagePayload | MessageCreateOptions | void>;
} | {
acceptsInteraction?: false;
run: RunFunction;
}
Och detta fungerade när jag skapade ett testkommando utanför allt så här:
const test1: Command = {
run: (mes, arg) => {}
}
VSCode visar snyggt de korrekta typerna av mes och arg även när jag lägger till eller tar bort egenskapen acceptsInteraction.
Men problemet börjar visa sig när jag försöker använda hela Module-objektet. Av någon anledning gillar inte TypeScript denna kod:
const test2: Module = {
commands: {
testcmd: {
run: (mes, arg) => {}
}
}
}
Det står att parametrarna mes och arg implicit har typen 'any'. Varför?
Det enda sättet jag kunde kringgå detta konstiga problem var att ta bort andra möjliga typer av kommandon som detta:
type Module = {
commands?: Record<string, Command>
}
Med modulen definierad på det här sättet visar VSCode återigen de korrekta typerna för de parametrarna. Men det är inte vad jag letade efter.
Om du tycker att detta tillvägagångssätt är dåligt och du har en bättre idé som passar mina behov, tveka inte att dela din åsikt.
Bara för att vara tydlig, jag vill bara konvertera vissa kommandon för att acceptera snedstreck-kommandot och därmed detta problem.
Här är också en TypeScript-lekplatslänk om det hjälper.
Tack i förväg.
Svar #1
Jag stötte på ett liknande problem när jag försökte typdefiniera mina slash-kommandon och sådant.
Detta är vad jag har funnit fungerar för mig:
export type SlashCommand = {
data: RESTPostAPIChatInputApplicationCommandsJSONBody | Omit<SlashCommandBuilder, "addSubcommandGroup" | "addSubcommand">
| SlashCommandSubcommandsOnlyBuilder;
userPermissions: Array<bigint>;
botPermissions: Array<bigint>;
run: (client: Client, interaction: ChatInputCommandInteraction) => Promise<any>;
}
Då har jag mina kommandon inställda som:
const commandName: SlashCommand = {
data: new SlashCommandBuilder()
.setName("commandName")
.setDescription("description")
.setDMPermission(false)
),
userPermissions: [],
botPermissions: [],
run: async (client, interaction) => {
//...
},
}
Men saker jag har stött på:
- När man lägger till underkommandon
.addSubcommand()måste jag avslutadata-parametern med.toJSON()(därav typenRESTPostAPIChatInputApplicationCommandsJSONBodyinomdata) - Jag kan verkligen inte lista ut hur man får underkommandogrupper att fungera och parsas korrekt... Men jag är säker på att det är en enkel lösning som jag inte hittar.
Tänkte jag skulle dela min improviserade lösning eftersom det inte finns något svar här än.
