TypeScript错误处理装饰器命名咨询:求合适命名方案
首先针对命名问题,你担心errorHandler会造成混淆是完全合理的——这个名字确实容易让人误解被装饰的函数本身是个错误处理器。这里有几个更清晰、表意准确的命名选项:
handleThrownErrors:直接点明装饰器的作用是处理被装饰函数抛出的错误,语义明确,不会产生歧义。withErrorHandling:强调这是给函数附加错误处理能力的装饰器,符合装饰器“增强原有功能”的定位。applyErrorHandlers:突出它会应用errorHandlerManager中配置的对应处理器,和你的实现逻辑完全匹配。catchAndHandle:简洁直观,直接描述了“捕获错误并处理”的核心行为。
接下来是对你现有实现的一些改进建议:
去掉冗余的
new Promise包装
你的被装饰函数是async函数,本身就会返回Promise,不需要再额外包裹一层new Promise,这样可以简化代码,也避免Promise嵌套的问题:function handleThrownErrors(errorHandlerManager: IErrorHandlerManager) { return (target: any, key: string | symbol, descriptor: PropertyDescriptor) => { const originalFn = descriptor.value; descriptor.value = async function (...args: any[]) { try { return await originalFn.apply(this, args); } catch (err: unknown) { if (!(err instanceof Error)) { // 处理非Error类型的抛出值 throw err; } const handler = errorHandlerManager.getHandler(err.constructor.name); if (typeof handler === 'function') { handler(err); // 建议把错误对象传给处理器,让它能获取错误详情 } else { throw err; } } }; }; }给错误处理器传递错误对象
原实现中handler()没有传入错误信息,这会让处理器无法获取错误的具体详情(比如消息、堆栈),几乎无法做有效的错误处理。修改为handler(err)能让处理器的实用性大大提升。处理非Error类型的抛出值
JavaScript/TypeScript中允许抛出任意类型的值(比如字符串、数字),你的原实现只处理Error类型,建议增加判断,避免类型错误,同时把非Error类型的抛出值重新抛出。考虑错误类型的继承关系
原实现通过err.constructor.name来匹配处理器,但如果有自定义错误继承自Error(比如class MyCustomError extends Error {}),constructor.name是MyCustomError,但如果errorHandlerManager只配置了Error的处理器,就无法匹配。你可以考虑添加一个遍历原型链的逻辑,查找最匹配的处理器:function getMatchingHandler(err: Error, manager: IErrorHandlerManager) { let currentConstructor = err.constructor; while (currentConstructor) { const handler = manager.getHandler(currentConstructor.name); if (handler) return handler; currentConstructor = Object.getPrototypeOf(currentConstructor); } return null; }然后在catch块中使用这个函数获取处理器。
保持this上下文的类型安全
如果你的装饰器用于类的方法,可以给target和this添加更具体的类型,比如用泛型:function handleThrownErrors<T>(errorHandlerManager: IErrorHandlerManager) { return (target: T, key: keyof T, descriptor: PropertyDescriptor) => { const originalFn = descriptor.value as (...args: any[]) => Promise<any>; descriptor.value = async function (this: T, ...args: any[]) { // ... 逻辑不变 }; }; }
内容的提问来源于stack exchange,提问作者Kiril Aleksandrov

