Discord.js v13开发机器人遭遇TypeError: Cannot read properties of undefined (reading 'set')错误,请求排查
你遇到的TypeError: Cannot read properties of undefined (reading 'set')错误,核心原因很明确:client.slash这个属性根本没被初始化,它默认是undefined,自然没法调用set方法。
为什么会出现这个问题?
看你贴的代码,你直接在client.slash.set(pull.name, pull)这一行调用了set方法,但从始至终都没有在client对象上创建slash这个存储命令的集合。JavaScript里访问一个不存在的对象属性会返回undefined,对undefined调用方法就会抛出这个错误。
解决步骤
1. 初始化client.slash为Discord.js Collection
Discord.js提供了Collection类(类似Map,但更适合存储命令这类键值对数据),我们需要先给client添加这个属性。有两种方式可以做到:
方式一:在主文件(index.js)中初始化
如果你是在index.js里创建的Discord客户端,直接在创建client后添加这一行:
const { Client, Collection, GatewayIntentBits } = require('discord.js'); // 注意:v13+需要指定intents,根据你的机器人需求调整 const client = new Client({ intents: [GatewayIntentBits.Guilds] }); // 初始化slash命令集合 client.slash = new Collection(); // 然后再加载你的slash模块 require('./structures/slash.js')(client); client.login('你的机器人令牌');
方式二:在slash.js模块内部初始化
如果不想修改主文件,也可以在slash.js的模块开头先导入Collection,然后在函数内部检查并初始化:
let slash = [] const { readdirSync } = require("fs"); const { Collection } = require("discord.js"); // 导入Collection const ascii = require("ascii-table"); let table = new ascii("Slash Commands"); table.setHeading('Slash Command', ' Load status'); module.exports = (client) => { // 初始化client.slash,如果它还不存在的话 if (!client.slash) { client.slash = new Collection(); } readdirSync("./Slash/").forEach(dir => { const commands = readdirSync(`./Slash/${dir}/`).filter(file => file.endsWith(".js")); for (let file of commands) { let pull = require(`../Slash/${dir}/${file}`); if (pull.name) { client.slash.set(pull.name, pull); // 现在client.slash存在了,不会报错 slash.push(pull); table.addRow(file, '✔️ -> Loaded Slash Command'); } else { table.addRow(file, `❌ -> missing a name property, or name is not a string.`); continue; } } }); console.log(table.toString()); client.on("ready",async ()=> { await client.guilds.cache.get('839096342953328691').commands.set(slash); }) }
2. 额外注意:确保ready事件能正确触发
如果你的主文件是先调用client.login()再加载slash模块,那么ready事件可能已经触发过了,导致命令注册的代码没执行。所以要确保先加载所有模块,再调用client.login()。
修改后的完整slash.js示例
let slash = [] const { readdirSync } = require("fs"); const { Collection } = require("discord.js"); const ascii = require("ascii-table"); let table = new ascii("Slash Commands"); table.setHeading('Slash Command', ' Load status'); module.exports = (client) => { // 初始化slash命令集合,兼容已存在的情况 client.slash = client.slash || new Collection(); readdirSync("./Slash/").forEach(dir => { const commands = readdirSync(`./Slash/${dir}/`).filter(file => file.endsWith(".js")); for (let file of commands) { let pull = require(`../Slash/${dir}/${file}`); if (pull.name) { client.slash.set(pull.name, pull); slash.push(pull); table.addRow(file, '✔️ -> Loaded Slash Command'); } else { table.addRow(file, `❌ -> missing a name property, or name is not a string.`); continue; } } }); console.log(table.toString()); // 用once替代on,避免重复注册命令 client.once("ready",async ()=> { const targetGuild = client.guilds.cache.get('839096342953328691'); if (!targetGuild) { console.error('无法找到目标服务器,请检查服务器ID是否正确'); return; } await targetGuild.commands.set(slash); console.log('Slash命令已成功注册到目标服务器'); }) }
我还帮你优化了两处细节:把client.on("ready")改成client.once("ready"),避免机器人重新登录时重复注册命令;另外加了服务器不存在的判断,防止后续出现新的错误。
内容的提问来源于stack exchange,提问作者Novato Original

