You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Discord斜杠命令注册时出现TypeError: Cannot read properties of undefined (reading 'toJSON')错误排查

Discord斜杠命令注册时出现TypeError: Cannot read properties of undefined (reading 'toJSON')错误排查

从你的描述和打印的CommandStore内容来看,问题的根源很明确:你的命令对象(BiodataCommand)并没有data属性,所以当你尝试调用command.data.toJSON()时,自然会抛出“无法读取undefined的toJSON属性”的错误。

结合你用的是Sapphire框架(从CommandStoreAliasPiece这些标识能看出来),我来帮你一步步排查修复:

1. 为什么会出现这个错误?

从你打印的BiodataCommand详情可以看到,你的命令类里只有applicationCommandRegistry但没有data字段,而你注册命令的代码却在尝试访问command.data——这完全不匹配。

Sapphire框架的命令类默认不会自动生成data属性,这个属性需要你自己在命令类里定义,或者你需要改用框架提供的命令注册方式,而不是直接用discord.js的rest.put逻辑硬套。

2. 修复步骤:先修正你的命令类

首先,你需要把biodata.js的命令类改成Sapphire框架下支持斜杠命令的正确写法,这里提供两种常用方式:

方式一:直接定义data属性(推荐用于需要手动批量注册的场景)

这种方式会给命令类添加data属性,刚好匹配你原来的注册代码逻辑:

const { Command } = require('@sapphire/framework');
const { SlashCommandBuilder } = require('discord.js');

class BiodataCommand extends Command {
  constructor(context, options) {
    super(context, {
      ...options,
      description: 'Send biodata form message'
    });
  }

  // 定义data属性,返回SlashCommandBuilder实例
  get data() {
    return new SlashCommandBuilder()
      .setName(this.name)
      .setDescription(this.description);
  }

  // 斜杠命令的执行逻辑
  async chatInputRun(interaction) {
    await interaction.reply('正在生成 biodata 表单...');
    // 这里写你的命令具体逻辑
  }
}

module.exports = { BiodataCommand };

方式二:用Sapphire内置的registerApplicationCommands方法

这是Sapphire框架推荐的命令注册方式,不需要手动处理rest.put,框架会帮你自动注册:

const { Command } = require('@sapphire/framework');

class BiodataCommand extends Command {
  constructor(context, options) {
    super(context, {
      ...options,
      description: 'Send biodata form message'
    });
  }

  // 让Sapphire自动注册斜杠命令
  registerApplicationCommands(registry) {
    registry.registerChatInputCommand((builder) =>
      builder.setName(this.name).setDescription(this.description)
    );
  }

  async chatInputRun(interaction) {
    await interaction.reply('正在生成 biodata 表单...');
  }
}

module.exports = { BiodataCommand };

如果用这种方式,你只需要确保Sapphire框架的API插件(@sapphire/plugin-api)已经正确配置,框架会自动处理命令的注册和同步,不需要你自己写rest.put的代码。

3. 调整你的注册代码(如果坚持手动注册)

如果你一定要用自己写的rest.put逻辑,那在修正命令类添加data属性之后,你的原有注册代码就能正常工作了。不过可以加个容错判断,避免其他命令出问题:

try {
  const commandStore = client.stores.get('commands');
  console.log(commandStore);
  
  const commands = commandStore.map(command => {
    if (!command.data) {
      throw new Error(`命令 ${command.name} 未定义data属性,请检查命令类写法`);
    }
    return command.data.toJSON();
  });

  console.log(`Registering ${commands.length} commands...`);
  await rest.put(Routes.applicationCommands(client.user.id), { body: commands });
  console.log('Commands registered successfully.');
} catch (error) {
  console.error('Error during command registration:', error);
}

4. 额外提醒:Sapphire框架的自动注册能力

其实你完全不需要手动写rest.put的代码,Sapphire的@sapphire/plugin-api插件可以自动帮你同步全局/服务器级的斜杠命令,只需要在框架初始化时配置好插件即可,这样能避免很多手动注册的坑。

内容来源于stack exchange

火山引擎 最新活动