Typescript 如何推导键值对类型实现 Discord.js 动态事件正确类型校验
实现方案
1. 重定义IBotEvent泛型接口
首先修改你的IBotEvent接口定义,通过泛型将事件名和对应的参数类型绑定:
import type { ClientEvents } from "discord.js"; // 泛型K约束为ClientEvents的键,默认为所有事件名的联合类型 export interface IBotEvent<K extends keyof ClientEvents = keyof ClientEvents> { name: K; once: boolean; execute: (...args: ClientEvents[K]) => Promise<void>; } // 可选:添加事件定义工厂函数,实现完全自动类型推导 export function defineEvent<K extends keyof ClientEvents>(event: IBotEvent<K>) { return event; }
2. 编写事件文件(两种可选写法)
推荐写法:工厂函数+对象字面量(无需手动指定泛型)
直接用刚才定义的defineEvent包裹事件配置,TS会根据name字段自动推导execute的参数类型,完全不需要手动写参数类型注解:
import { defineEvent } from "../interfaces"; export default defineEvent({ name: "ready", once: true, // 自动推导参数为Client<true>类型,无需手动声明 execute: async (client) => { console.log(`登录成功,账号:${client.user.tag}`); } });
如果是多参数的事件同样适用,比如emojiUpdate:
export default defineEvent({ name: "emojiUpdate", once: false, // 自动推导两个参数分别为GuildEmoji、GuildEmoji类型 execute: async (oldEmoji, newEmoji) => { console.log(`表情更新:${oldEmoji.name} -> ${newEmoji.name}`); } });
类写法
如果你坚持用类实现,只要给IBotEvent传入对应事件名的泛型参数即可:
import type { IBotEvent } from "../interfaces"; import type { ClientEvents } from "discord.js"; export default class ReadyEvent implements IBotEvent<"ready"> { name = "ready" as const; once = true as const; // 参数自动推导为Client<true>类型 async execute(client) { console.log(`登录成功,账号:${client.user.tag}`); } }
3. 调整主文件注册逻辑
主文件的注册逻辑只需要微调,因为我们的接口定义已经保证了event.execute的参数和事件名对应的参数完全匹配,所以这里的any[]是类型安全的:
const eventFiles = fs .readdirSync("./events") .filter((file) => file.endsWith(".ts")); eventFiles.forEach(async (file) => { // 如果是用工厂函数导出的字面量,直接取default即可;如果是类导出,需要new一下 const event = (await import(`./events/${file}`)).default as IBotEvent; if (event.once) { this.once(event.name, (...args: any[]) => event.execute(...args)); } else { this.on(event.name, (...args: any[]) => event.execute(...args)); } });
实现原理
核心是利用TS的泛型约束和元组映射:将IBotEvent的泛型参数K约束为ClientEvents的键,execute的参数直接映射为ClientEvents[K]对应的元组类型,TS会自动完成类型推导和校验,不需要手动复制参数定义。
内容的提问来源于stack exchange,提问作者Legiit
相关产品推荐
相关产品推荐

