如何在Discord.js中从异步函数获取SlashCommand选项选择项?
问题
尝试创建名为/test3的Discord.js斜杠命令,命令包含带选择项的input选项,希望从异步函数getArgumentList获取选择项,但当前实现报错。相关代码如下:
tools.js 代码
module.exports = { getArgumentList: () => getArgumentList() } async function getArgumentList(){ return [ {name: '1', value:'One'}, {name: '2', value:'Two'}, {name: '3', value:'Three'}, {name: '4', value:'Four'}, {name: '5', value:'Five'} ] }
test3.js 命令代码
const { SlashCommandBuilder } = require("discord.js"); const { getArgumentList } = require("../tools.js") module.exports = { data: new SlashCommandBuilder() .setName('test3') .setDescription('Test command for commands with options.') .addStringOption(option => getArgumentList() .then(list => option.setName('input') .setDescription('The input to echo back.') .setChoices(...list) )), async execute(interaction){ console.log('Testing') } }
报错信息
ExpectedValidationError: Expected at InstanceValidator.handle ... at Module._load (node:internal/modules/cjs/loader:922:12) { validator: 's.instance(V)', given: Promise { <pending> }, expected: [Function: SlashCommandStringOption] } Node.js v18.13.0
报错原因
addStringOption的回调函数要求返回SlashCommandStringOption实例,但你当前返回的是getArgumentList()执行后的Promise对象,Discord.js无法识别这个Promise类型,因此抛出类型验证错误。
解决方法
情况1:getArgumentList不需要真正异步(示例场景)
如果你的getArgumentList只是模拟异步逻辑,实际无需异步操作,直接改为同步函数即可:
修改 tools.js:
module.exports = { getArgumentList: () => getArgumentList() } // 去掉async关键字,改为同步函数 function getArgumentList(){ return [ {name: '1', value:'One'}, {name: '2', value:'Two'}, {name: '3', value:'Three'}, {name: '4', value:'Four'}, {name: '5', value:'Five'} ] }
修改 test3.js:
const { SlashCommandBuilder } = require("discord.js"); const { getArgumentList } = require("../tools.js") module.exports = { data: new SlashCommandBuilder() .setName('test3') .setDescription('Test command for commands with options.') .addStringOption(option => option.setName('input') .setDescription('The input to echo back.') .setChoices(...getArgumentList())), // 直接调用同步函数获取选项 async execute(interaction){ console.log('Testing') } }
情况2:getArgumentList确实需要异步(如从数据库/API拉取数据)
Discord.js的命令注册阶段是同步的,无法直接在data属性中使用异步操作。此时需要提前在命令加载阶段获取异步数据,再构建命令:
修改 test3.js 为异步加载形式:
const { SlashCommandBuilder } = require("discord.js"); const { getArgumentList } = require("../tools.js") // 异步构建命令数据 async function buildCommandData() { const list = await getArgumentList(); return new SlashCommandBuilder() .setName('test3') .setDescription('Test command for commands with options.') .addStringOption(option => option.setName('input') .setDescription('The input to echo back.') .setChoices(...list)); } // 导出异步函数,在命令注册时调用 module.exports = async () => { const data = await buildCommandData(); return { data, async execute(interaction) { console.log('Testing'); } }; };
然后修改你的命令注册脚本,异步加载该模块:
// 命令注册文件示例 const fs = require('fs'); const path = require('path'); const { REST, Routes } = require('discord.js'); async function registerCommands() { const commands = []; const commandsPath = path.join(__dirname, 'commands'); const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); for (const file of commandFiles) { const filePath = path.join(commandsPath, file); const commandModule = require(filePath); // 判断模块是否为异步函数,是则先调用获取命令对象 const command = typeof commandModule === 'function' ? await commandModule() : commandModule; commands.push(command.data.toJSON()); } // 后续REST注册逻辑(省略) } registerCommands();
内容的提问来源于stack exchange,提问作者GD Clone
相关产品推荐
相关产品推荐

