You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复JS中Cannot read properties of undefined (reading '0')错误

Discord.js /script命令选择菜单 TypeError 错误修复

错误信息

TypeError: Cannot read properties of undefined (reading '0')

问题场景

开发Discord机器人的/script命令时,调用API测试触发上述错误。代码尝试通过const value = interaction.values[0];获取选择菜单的值,但用户选择选项后无法发送对应数据。

核心问题分析

  1. 错误根源:初始的Slash Command交互对象中不存在values属性,该属性仅在用户触发选择菜单点击事件时才会生成。代码在发送选择菜单后立即读取interaction.values,必然抛出undefined错误。
  2. 重复回复冲突:即便获取到值,重复调用interaction.reply()会报错,因为同一交互只能回复一次,后续操作需使用update()或followUp()。
  3. SQL注入风险:直接将用户ID拼接进SQL语句,存在注入漏洞。
  4. 异步回调混乱:使用回调方式处理SQL查询,导致代码嵌套复杂且无法正确捕获异步错误。

修复后的完整代码

const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require('discord.js');
function makeid(length) {
    var result = '';
    var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for (var i = 0; i < length; i++) {
        result += characters.charAt(Math.floor(Math.random() * charactersLength));
    }
    return result;
}

module.exports = {
    data: new SlashCommandBuilder()
        .setName('script')
        .setDescription('รับสคริป'),
    execute: async (interaction, con, log, client, config) => {
        log(`[LOG Command] ${interaction.user.username}, use command getscript`, "green");

        const menu = new ActionRowBuilder().addComponents(
            new StringSelectMenuBuilder()
                .setCustomId("SCRIPT_SELECT")
                .addOptions(
                    { label: "BloxFruit", description: "script BloxFruit ", value: "BF", emoji: "🍎" },
                    { label: "City Thiland", description: "script City Thiland 2", value: "CTTH", emoji: "🏙" }
                )
        );

        try {
            // 参数化查询防SQL注入
            const [results] = await con.promise().query(
                `SELECT userkey, discord_id, Blacklisted FROM bloxfruit WHERE discord_id = ?`,
                [interaction.user.id]
            );

            if (!results[0]) {
                await interaction.reply({
                    embeds: [
                        new EmbedBuilder()
                            .setColor("#FF0000")
                            .setTitle('**"WET HUB" | ᴡʜɪᴛᴇʟɪsᴛ ᴍᴀɴᴀɢᴇʀ**')
                            .setDescription("คุณไม่มีไวริสนะคะ กรุณาก่อนใช้ด้วยค่ะ")
                            .setTimestamp()
                    ],
                    ephemeral: true
                });
                return;
            }

            if (results[0].Blacklisted === "True") {
                await interaction.reply({
                    embeds: [
                        new EmbedBuilder()
                            .setColor("#FF0000")
                            .setTitle('**WET HUB | ᴡʜɪᴛᴇʟɪsᴛ ᴍᴀɴᴀɢᴇʀ**')
                            .setDescription("คุณอยู่ในบัญชีดำนะคะ")
                            .setTimestamp()
                    ],
                    ephemeral: true
                });
                return;
            }

            const key = results[0].userkey;
            const discord_id = results[0].discord_id;

            // 发送选择菜单
            await interaction.reply({
                content: "请选择你需要的脚本:",
                ephemeral: true,
                components: [menu]
            });

            // 监听选择菜单交互,仅响应命令发起者
            const filter = i => i.customId === 'SCRIPT_SELECT' && i.user.id === interaction.user.id;
            const collector = interaction.channel.createMessageComponentCollector({ filter, time: 60000 });

            collector.on('collect', async i => {
                const value = i.values[0];
                let embed;

                switch (value) {
                    case "BF":
                    case "CTTH":
                        embed = new EmbedBuilder()
                            .setColor("00FF46")
                            .setTitle('**WET HUB | ᴡʜɪᴛᴇʟɪsᴛ ᴍᴀɴᴀɢᴇʀ**')
                            .setDescription(`\`\`\`lua
getgenv().Key = "${key}"
getgenv().DiscordId = "${discord_id}"
loadstring(game:HttpGet("https://raw.githubusercontent.com/Galiverking/CheckPointWT/main/check-lua.lua"))()
\`\`\``)
                            .setTimestamp();
                        break;
                    default:
                        embed = new EmbedBuilder()
                            .setColor("#FF0000")
                            .setTitle('错误')
                            .setDescription("无效的选择");
                }

                // 更新原消息,替换为脚本内容并移除菜单
                await i.update({
                    content: "",
                    embeds: [embed],
                    components: []
                });
                collector.stop();
            });

            // 超时处理
            collector.on('end', collected => {
                if (collected.size === 0) {
                    interaction.editReply({
                        content: "选择超时,请重新执行命令。",
                        components: []
                    }).catch(console.error);
                }
            });

        } catch (err) {
            console.error("数据库查询错误:", err);
            await interaction.reply({
                content: "执行命令时发生错误,请稍后重试。",
                ephemeral: true
            });
        }
    }
};

关键修复说明

  • 交互监听逻辑:使用MessageComponentCollector监听用户的选择菜单点击事件,仅在用户触发交互时读取i.values[0],彻底解决undefined错误。
  • SQL注入防护:采用参数化查询方式,避免直接拼接用户输入,杜绝SQL注入风险。
  • 异步处理优化:将SQL查询改为Promise化调用,配合try/catch捕获异常,代码结构更清晰且错误处理更完善。
  • 消息操作修正:使用i.update()更新原消息,避免重复回复的冲突问题。
  • 超时与权限控制:添加60秒交互超时,同时限制仅命令发起者可操作选择菜单,提升安全性。
  • 代码清理:移除未使用的变量和导入,修正选择菜单CustomId的拼写错误。

内容的提问来源于stack exchange,提问作者GaliverKing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 17:17:55