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
相关产品推荐
相关产品推荐

