TypeScript中如何实例化动态加载的自定义类?
问题根因
- TypeScript 编译为ES模块时,
export class XXX的导出会被挂载到模块导出对象的属性上,而非直接将导出对象设置为构造函数,因此直接require得到的是包含构造函数的对象,不是可实例化的类本身。 - 原有
getRuleValidator方法在首次加载验证器后错误返回null,会导致首次调用时报错。 - 异步import方案报错的原因是直接调用了模块导出对象的
validate方法,而非先实例化类再调用实例方法。
解决方案(同步require实现,无需改动现有业务逻辑)
方案1:修改验证器导出为default导出(推荐,后续新增验证器无需调整加载逻辑)
在每个验证器类文件末尾补充default导出:
// WeightValidator.ts 末尾新增 export default WeightValidator
修正getRuleValidator方法逻辑:
private getRuleValidator(validatorName: string): RuleValidator { validatorName = validatorName?.toLocaleLowerCase() ?? ''; // 命中缓存直接返回 if (this.validators[validatorName]) { return this.validators[validatorName] as RuleValidator; } // 动态加载模块 const moduleExports = require(`../ruleValidator/${validatorName}`); // 兼容ES模块与CommonJS导出格式 const ValidatorConstructor = moduleExports.default ?? moduleExports; // 实例化并存入缓存 const validatorInstance = new ValidatorConstructor() as RuleValidator; this.validators[validatorName] = validatorInstance; return validatorInstance; }
方案2:不修改现有验证器导出,通过类名匹配导出属性
如果不想调整现有验证器的导出写法,可通过规则拼接导出的类名读取构造函数:
private getRuleValidator(validatorName: string): RuleValidator { validatorName = validatorName?.toLocaleLowerCase() ?? ''; if (this.validators[validatorName]) { return this.validators[validatorName] as RuleValidator; } const moduleExports = require(`../ruleValidator/${validatorName}`); // 按命名规则拼接导出的类名 例如 weight -> WeightValidator const exportClassName = `${validatorName.charAt(0).toUpperCase()}${validatorName.slice(1)}Validator`; const ValidatorConstructor = moduleExports[exportClassName]; const validatorInstance = new ValidatorConstructor() as RuleValidator; this.validators[validatorName] = validatorInstance; return validatorInstance; }
注意事项
- 确保验证器文件名与传入的
validatorName小写格式完全匹配,例如weight对应weight.ts - 检查
tsconfig.json中esModuleInterop配置项设为true,可自动处理ES模块与CommonJS的导出兼容 - 修正
RulesEngineService的类定义语法错误:移除类名后的括号,正确写法为export class RulesEngineService {
内容的提问来源于stack exchange,提问作者SpaceCowboy74
相关产品推荐
相关产品推荐

