如何编写兼容类方法与字段函数的TypeScript 5类型安全装饰器工厂
实现兼容类方法与字段函数的TypeScript 5类型安全装饰器工厂
要解决这个问题,核心是利用函数重载明确区分方法装饰器与字段装饰器的签名差异,同时在实现中分别处理两种场景的逻辑。以下是完整的类型安全解决方案:
完整代码实现
import { TypedPropertyDescriptor } from "typescript"; // 重载1:适配类方法(含实例方法、静态方法) function customLogger<T extends (...args: any[]) => Promise<any>>( target: any, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T> ): TypedPropertyDescriptor<T> | void; // 重载2:适配类字段函数(含实例字段、静态字段) function customLogger<T extends (...args: any[]) => Promise<any>>( target: any, propertyKey: string | symbol ): (initialValue: T) => T; // 通用实现逻辑 function customLogger( target: any, propertyKey: string | symbol, descriptor?: PropertyDescriptor ) { // 场景1:处理类方法(存在descriptor参数) if (descriptor) { const originalMethod = descriptor.value as (...args: any[]) => Promise<any>; descriptor.value = async function (...args: any[]) { console.log(`[LOG] 调用方法 ${String(propertyKey)},参数:`, args); try { const result = await originalMethod.apply(this, args); console.log(`[LOG] 方法 ${String(propertyKey)} 执行成功,结果:`, result); return result; } catch (error) { console.error(`[LOG] 方法 ${String(propertyKey)} 执行失败,错误:`, error); throw error; } }; return descriptor; } // 场景2:处理类字段函数(无descriptor参数) else { return function (initialValue: (...args: any[]) => Promise<any>) { return async function (...args: any[]) { console.log(`[LOG] 调用字段函数 ${String(propertyKey)},参数:`, args); try { const result = await initialValue.apply(this, args); console.log(`[LOG] 字段函数 ${String(propertyKey)} 执行成功,结果:`, result); return result; } catch (error) { console.error(`[LOG] 字段函数 ${String(propertyKey)} 执行失败,错误:`, error); throw error; } }; }; } }
使用示例
class DemoService { // 实例字段函数 @customLogger asyncField = async (input: number): Promise<number> => { return input * 3; }; // 实例方法 @customLogger async asyncMethod(input: string): Promise<string> { return `处理结果:${input}`; } // 静态字段函数 @customLogger static staticAsyncField = async (msg: string): Promise<string> => { return `静态字段:${msg}`; }; // 静态方法 @customLogger static async staticAsyncMethod(msg: string): Promise<string> { return `静态方法:${msg}`; } }
关键细节说明
重载区分场景
- 方法装饰器的签名包含
descriptor参数,返回值为TypedPropertyDescriptor<T> | void,用于修改方法的属性描述符 - 字段装饰器无
descriptor参数,返回值为一个初始化函数,用于在字段赋值时包装原函数
- 方法装饰器的签名包含
类型安全保障
- 通过泛型
T extends (...args: any[]) => Promise<any>约束装饰器仅作用于异步函数 - 保留原函数的
this绑定(使用普通函数而非箭头函数),确保原函数的上下文行为不变
- 通过泛型
TypeScript配置要求
需在tsconfig.json中启用装饰器相关配置:{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true, "target": "ES2022" // 或更高版本,支持异步函数语法 } }
内容的提问来源于stack exchange,提问作者Jialiang T.
相关产品推荐
相关产品推荐

