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

Discord消息组件TypeScript类型不匹配问题求助

问题:Discord机器人从JS转TS后消息组件类型不匹配错误

我正在把Discord机器人从JavaScript重写为TypeScript,创建消息组件时遇到了类型不兼容的问题。在JS里可以直接用ActionRowBuilder/ButtonBuilder传入Channel的.send()方法,但TS里触发了类型错误。

依赖版本

├── @discordjs/rest@1.3.0
├── @types/node@18.11.9
├── discord.js@14.6.0
├── dotenv@16.0.3
├── mysql2@2.3.3
├── nodemon@2.0.20
├── reflect-metadata@0.1.13
├── ts-node@10.9.1
├── typeorm@0.3.10
└── typescript@4.9.3

类型定义

export type MessageComponents = {
    content?: string;
    messageComponents?: ActionRowBuilder<AnyComponentBuilder>[];
    messageEmbeds?: APIEmbed;
}

构建代码

export default class MessageEditor {
    public buildMessage(saniResponses: SanitizedApplicationText, id: number): MessageComponents {
        const embed = new EmbedBuilder()
            .setColor(ApplicationEmbedColors.PENDING)
            .setDescription(saniResponses.appText)
            .setTitle(saniResponses.appTitle);

        const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
            new ButtonBuilder()
                .setCustomId(`apply_button_accept_${id}`)
                .setLabel('✅ Accept')
                .setStyle(ButtonStyle.Success),

            new ButtonBuilder()
                .setCustomId(`apply_button_deny_${id}`)
                .setLabel('🐍 Deny')
                .setStyle(ButtonStyle.Danger)
        );

        return { messageComponents: [row], messageEmbeds: embed }
    };
}

使用代码

const applicationLogChannel = await client.channels.fetch(guildConfig.applicationLogChannelId) as TextChannel;
const message = await new ApplicationFormFunctions().sanitzeApplication(client, completedApp!);
if (!message || !message.messageComponents || !message.messageEmbeds) { return; }
await applicationLogChannel.send({
    components: message.messageComponents,
    embeds: [message.messageEmbeds],
});

报错信息

类型 'ActionRowBuilder<AnyComponentBuilder>[]' 无法分配给类型 '(APIActionRowComponent<APIMessageActionRowComponent> | JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>> | ActionRowData<...>)[]'。
  类型 'ActionRowBuilder<AnyComponentBuilder>' 无法分配给类型 'APIActionRowComponent<APIMessageActionRowComponent> | JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>> | ActionRowData<...>'。
    类型 'ActionRowBuilder<AnyComponentBuilder>' 中缺少属性 'type',但类型 'ActionRowData<MessageActionRowComponentBuilder | MessageActionRowComponentData>' 中需要该属性。ts(2322)

解决方案

1. 修正类型定义的类型不匹配

  • messageEmbeds类型错误:你返回的是EmbedBuilder实例,但类型定义写的是APIEmbed,二者不兼容。可以把类型改为EmbedBuilder,或者后续用toJSON()转换为APIEmbed。
  • messageComponents的泛型可以更精确,用ActionRowBuilder<MessageActionRowComponentBuilder>[]代替宽泛的AnyComponentBuilder,避免类型歧义。

修改后的类型定义:

import { ActionRowBuilder, EmbedBuilder, MessageActionRowComponentBuilder } from 'discord.js';

export type MessageComponents = {
    content?: string;
    messageComponents?: ActionRowBuilder<MessageActionRowComponentBuilder>[];
    messageEmbeds?: EmbedBuilder;
}

2. 调整组件构建的泛型约束

创建ActionRowBuilder时,指定泛型为MessageActionRowComponentBuilder(按钮属于这个类型),确保和后续send()方法的参数类型匹配:

export default class MessageEditor {
    public buildMessage(saniResponses: SanitizedApplicationText, id: number): MessageComponents {
        const embed = new EmbedBuilder()
            .setColor(ApplicationEmbedColors.PENDING)
            .setDescription(saniResponses.appText)
            .setTitle(saniResponses.appTitle);

        const row = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
            new ButtonBuilder()
                .setCustomId(`apply_button_accept_${id}`)
                .setLabel('✅ Accept')
                .setStyle(ButtonStyle.Success),

            new ButtonBuilder()
                .setCustomId(`apply_button_deny_${id}`)
                .setLabel('🐍 Deny')
                .setStyle(ButtonStyle.Danger)
        );

        return { messageComponents: [row], messageEmbeds: embed };
    };
}

3. 可选:转换为可序列化结构(兜底方案)

如果还是有类型问题,可以在发送消息时,调用每个组件和嵌入的toJSON()方法,转换为Discord.js接受的API结构:

await applicationLogChannel.send({
    components: message.messageComponents.map(row => row.toJSON()),
    embeds: [message.messageEmbeds.toJSON()],
});

此时需要把MessageComponents的messageEmbeds类型改为APIEmbed,同时在构建方法中返回embed.toJSON()。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:55:31