在TypeScript中为Discord机器人兼容消息与交互命令的类型问题
问题解决方案
1. 拆分类型定义,避免联合类型模糊
先把不同类型的命令成员拆分,明确边界,让TypeScript能正确进行类型推断:
// 保留原有基础类型 type RunFunction = (message: Message, arg: string) => Awaitable<string | MessagePayload | MessageCreateOptions | void>; type SimpleCommandResponse = string; // 拆分支持交互的Command和普通Command type InteractionSupportedCommand = { acceptsInteraction: true; run: (interactionOrMessage: CommandInteraction | Message, arguments?: string) => Awaitable<string | MessagePayload | MessageCreateOptions | void>; }; type BasicCommand = { acceptsInteraction?: false; run: RunFunction; }; // 重新定义Command联合类型 type Command = InteractionSupportedCommand | BasicCommand; // 重新定义Module的commands,用明确的联合类型替代宽泛的Record type Module = { commands?: Record<string, SimpleCommandResponse | RunFunction | Command>; };
2. 用类型守卫强化类型推断
在执行命令的逻辑中,添加类型守卫函数,帮助TypeScript收缩类型,避免参数被推断为any:
// 判断是否为支持交互的命令 function isInteractionCommand(cmd: SimpleCommandResponse | RunFunction | Command): cmd is InteractionSupportedCommand { return typeof cmd === 'object' && 'acceptsInteraction' in cmd && cmd.acceptsInteraction === true; } // 判断是否为普通Command对象 function isBasicCommand(cmd: SimpleCommandResponse | RunFunction | Command): cmd is BasicCommand { return typeof cmd === 'object' && (!('acceptsInteraction' in cmd) || cmd.acceptsInteraction === false); } // 命令执行示例 async function executeCommand(cmd: SimpleCommandResponse | RunFunction | Command, trigger: Message | CommandInteraction, args?: string) { if (typeof cmd === 'string') { // 处理直接回复字符串的命令 await sendResponse(trigger, cmd); } else if (typeof cmd === 'function') { // 处理普通RunFunction,仅允许Message触发 if (trigger instanceof Message) { await cmd(trigger, args || ''); } } else if (isInteractionCommand(cmd)) { // 处理支持交互的命令 await cmd.run(trigger, args); } else if (isBasicCommand(cmd)) { // 处理普通Command对象,仅允许Message触发 if (trigger instanceof Message) { await cmd.run(trigger, args || ''); } } } // 统一发送响应的工具函数 async function sendResponse(trigger: Message | CommandInteraction, content: string | MessagePayload | MessageCreateOptions) { if (trigger instanceof Message) { await trigger.reply(content); } else { await trigger.reply(typeof content === 'string' ? content : { ...content }); } }
3. 可选优化:标签联合类型(Tagged Union)
如果后续需要扩展更多命令类型,建议给每个命令类型添加明确的type标签,进一步提升类型推断的可靠性:
type RunFunction = (message: Message, arg: string) => Awaitable<string | MessagePayload | MessageCreateOptions | void>; type SimpleCommand = { type: 'simple'; response: string; }; type BasicFunctionCommand = { type: 'basic-function'; run: RunFunction; }; type InteractionCommand = { type: 'interaction'; run: (interactionOrMessage: CommandInteraction | Message, arguments?: string) => Awaitable<string | MessagePayload | MessageCreateOptions | void>; }; // 所有命令类型的联合 type Command = SimpleCommand | BasicFunctionCommand | InteractionCommand; type Module = { commands?: Record<string, Command>; };
这种方式下,只需判断type字段就能精准区分命令类型,彻底避免联合类型模糊导致的推断问题。
内容的提问来源于stack exchange,提问作者Histmy
相关产品推荐
相关产品推荐

