调试TypeScript类try/catch装饰器:Reflect.ownKeys仅返回constructor
类装饰器无法捕获箭头函数方法的错误?问题出在方法定义方式上
你的核心问题是类里的方法用了箭头函数定义,导致装饰器遍历原型时找不到它,根本没完成方法包装,自然不会触发错误回调。
问题根源
你写的getScorecard是类字段箭头函数,这种写法会把方法挂载到类的实例上,而不是类的prototype原型链上。而你的装饰器逻辑只遍历了target.prototype,所以Reflect.ownKeys(target.prototype)只能拿到constructor,完全碰不到这个箭头函数方法,装饰器的错误包装逻辑根本没作用在它上面。
解决方案
方案1:把箭头函数改成原型方法(推荐)
这是类方法的标准写法,方法会挂载到原型上,你的原有装饰器逻辑就能正常遍历包装:
@TryCatchClassDecorator(EagerLoadingError, (err, context) => { console.log(context, err); // 现在会正常打印日志 throw err; }) class TaskDAO { constructor() {} // 改成普通async方法,挂载到原型 public async getScorecard(providerName: ProviderEnum, batchNum: number) { return await Task.findAll({ where: { providerName }, include: { model: Batch, where: { batchId: batchNum } } }); }; }
方案2:如果必须用箭头函数(比如需要绑定this),修改装饰器逻辑
如果一定要保留箭头函数写法,就得让装饰器在实例化时处理实例的自有属性,而不是只遍历原型:
function TryCatchClassDecorator(errorType: any, handler: (err: any, context: any) => void) { return function(target: Function) { const originalConstructor = target; // 重写构造函数,在实例化时包装箭头函数方法 function NewConstructor(...args: any[]) { const instance = new originalConstructor(...args); // 遍历实例的自有属性,找到箭头函数方法 for (const propName of Object.getOwnPropertyNames(instance)) { const propValue = instance[propName]; // 跳过构造函数,只处理函数类型的属性 if (typeof propValue === 'function' && propName !== 'constructor') { // 包装异步方法的错误处理 instance[propName] = async function(...innerArgs: any[]) { try { return await propValue.apply(this, innerArgs); } catch (err) { if (err instanceof errorType) { handler(err, { method: propName, args: innerArgs }); } throw err; } }; } } return instance; } // 保持原型链和类名一致,避免破坏原有结构 NewConstructor.prototype = originalConstructor.prototype; Object.defineProperty(NewConstructor, 'name', { value: originalConstructor.name }); return NewConstructor as unknown as typeof target; }; }
验证效果
修改后,当getScorecard抛出SequelizeEagerLoadingError时,装饰器的回调会正常执行,打印日志后重新抛出错误,你就能看到完整的错误栈信息了。
内容的提问来源于stack exchange,提问作者plutownium
相关产品推荐
相关产品推荐

