TypeScript开发discord.js v13机器人报require(...) is not a constructor错误如何解决
问题修复方案
错误原因
这个报错本质是两个核心问题叠加导致的:
- 你的命令类使用具名导出,
require()返回的是包含所有导出内容的对象,而非直接的构造函数,直接调用new require(xxx)自然会提示不是构造函数 - 命令类的构造函数要求传入
HeavensBot客户端实例,你当前初始化时没有传入任何参数,就算导出逻辑正确也会报错
另外还有两处隐藏的逻辑问题:
- 你在Base基类里把
help、conf属性声明为private,外部代码无法直接访问,后续设置命令和别名时也会抛出访问权限错误 - 你使用了异步回调式的
fs.readdir,外层的async关键字没有实际作用,也没有统一的错误捕获逻辑
修复步骤
1. 调整命令类的导出方式(二选一即可)
方案A:改为默认导出
把每个命令文件的导出逻辑改为默认导出,以Ping命令为例:
import { Message } from "discord.js"; import { HeavensBot } from "../HeavensBot"; import { Command as Base } from "../util/Base"; // 把原来的export class Ping改成默认导出 export default class Ping extends Base { constructor(client: HeavensBot) { super(client, { name: "ping", description: "Ping command", aliases: [], }); } run(message: Message, args: string[]) { const start = Date.now(); message.reply({ content: `Pong! Took ${Date.now() - start}ms`, }); } }
方案B:保留具名导出
如果不想修改现有导出方式,后续加载时指定对应导出的类名即可。
2. 修改Base基类的属性访问权限
把help和conf的private修饰符改为public,或者单独添加对应的getter方法:
import { HeavensBot } from "../HeavensBot"; interface CommandOptions { name: string; description: string; aliases: string[]; } interface CommandDotHelp { name: string; description: string; } interface Configuration { aliases: string[]; } export class Command { private client: HeavensBot; // 把private改为public允许外部访问 public help: CommandDotHelp; public conf: Configuration; constructor(client: HeavensBot, options: CommandOptions) { this.client = client; this.help = { name: options.name, description: options.description, } this.conf = { aliases: options.aliases, } } }
3. 重写loadCommands加载函数
修复加载逻辑,补充参数传入,建议用fs的Promise API适配async异步写法,同时解决路径适配问题:
import { promises as fs } from 'fs'; import path from 'path'; async loadCommands(): Promise<void> { try { const commandPath = path.resolve(__dirname, './Commands'); const files = await fs.readdir(commandPath); for (const file of files) { // 过滤非代码文件 if (!file.endsWith('.ts') && !file.endsWith('.js')) continue; // 去掉后缀获取模块名 const fileName = file.slice(0, file.lastIndexOf('.')); // 导入模块:方案A默认导出取.default const CommandClass = require(path.join(commandPath, fileName)).default; // 如果用方案B具名导出,类名和文件名一致的话用下面的写法 // const CommandClass = require(path.join(commandPath, fileName))[fileName]; // 传入当前client实例初始化命令 const command = new CommandClass(this); this.commands.set(command.help.name, command); command.conf.aliases.forEach((alias: string) => { this.aliases.set(alias, command.help.name); }); } } catch (err) { console.error('命令加载失败:', err); } }
内容的提问来源于stack exchange,提问作者SKKYZ3R
相关产品推荐
相关产品推荐

