装饰器调用引用自身类方法触发初始化错误,如何解决?
装饰器引用自身类方法报错的解决办法
尝试给装饰器传递自身类的实例方法作为参数时遇到了ReferenceError: Cannot access 'SomeClass' before initialization错误,示例代码如下:
export class SomeClass { public async handleError(error: Error): Promise<void> { // ... 处理错误 } @treat(SomeClass.prototype.handleError) // <- 此处报错 public async doSomething(): Promise<void> { // ... 执行操作 } }
这是因为类定义还未完成初始化时,装饰器就已经执行了,此时SomeClass还未被完全创建,无法访问其prototype属性。下面提供几种可行的解决办法:
方法一:传递方法名称,在装饰器内动态查找
这是最直接的方案,把方法名作为字符串传给装饰器,在装饰器内部通过实例去获取对应的方法:
// 装饰器实现 function treat(methodName: string) { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = async function(...args: any[]) { try { await originalMethod.apply(this, args); } catch (error) { // 通过this访问实例上的处理方法 await this[methodName](error as Error); } }; return descriptor; }; } // 使用装饰器 export class SomeClass { public async handleError(error: Error): Promise<void> { // ... 处理错误 } @treat('handleError') // 传递方法名称 public async doSomething(): Promise<void> { // ... 执行操作 } }
方法二:将处理方法改为静态方法
如果handleError不需要访问实例属性,可以改成静态方法,这样就能在装饰器中直接引用:
// 装饰器实现 function treat(errorHandler: (error: Error) => Promise<void>) { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = async function(...args: any[]) { try { await originalMethod.apply(this, args); } catch (error) { await errorHandler(error as Error); } }; return descriptor; }; } // 使用装饰器 export class SomeClass { public static async handleError(error: Error): Promise<void> { // ... 处理错误(无实例属性访问) } @treat(SomeClass.handleError) // 直接引用静态方法 public async doSomething(): Promise<void> { // ... 执行操作 } }
方法三:利用类装饰器统一处理
如果多个方法都需要错误处理,可以用类装饰器遍历类的方法,统一绑定错误处理逻辑:
// 类装饰器实现 function TreatAllErrors() { return function(constructor: Function) { const proto = constructor.prototype; // 遍历实例方法 Object.getOwnPropertyNames(proto).forEach(methodName => { if (methodName !== 'constructor' && methodName !== 'handleError') { const originalMethod = proto[methodName]; proto[methodName] = async function(...args: any[]) { try { await originalMethod.apply(this, args); } catch (error) { await this.handleError(error as Error); } }; } }); }; } // 使用类装饰器 @TreatAllErrors() export class SomeClass { public async handleError(error: Error): Promise<void> { // ... 处理错误 } public async doSomething(): Promise<void> { // ... 执行操作 } }
方法四:将处理函数移到类外部
如果handleError的逻辑不依赖类的实例或静态属性,可以直接把它定义在类外面,装饰器就能直接引用:
// 外部处理函数 export async function handleError(error: Error): Promise<void> { // ... 处理错误 } // 装饰器实现 function treat(errorHandler: (error: Error) => Promise<void>) { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = async function(...args: any[]) { try { await originalMethod.apply(this, args); } catch (error) { await errorHandler(error as Error); } }; return descriptor; }; } // 使用装饰器 export class SomeClass { @treat(handleError) // 直接引用外部函数 public async doSomething(): Promise<void> { // ... 执行操作 } }
内容的提问来源于stack exchange,提问作者his dudeness
相关产品推荐
相关产品推荐

