如何使用TypeScript方法装饰器强制方法必须包含executionTime参数
实现方案
核心逻辑说明
通过方法装饰器在类加载阶段自动校验被装饰方法的参数列表,如果不存在executionTime参数直接抛出错误,同时可以额外增加TS类型校验实现编译期提前报错。
完整代码实现
class AllEvents { @performanceDecorator() public static firstEvent(param1: string, param2: string, executionTime: number): void { //some tasks... } // 该方法会触发错误提示 @performanceDecorator() public static secondEvent(param1: string, param2: string): void { //some tasks... } @performanceDecorator() public static thirdEvent(param1: string, param2: string, executionTime: number): void { //some tasks... } } /** * 性能采集装饰器工厂,可传入自定义配置参数 */ function performanceDecorator() { // 装饰器执行逻辑 return function (target: any, methodName: string | symbol, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; // 提取方法的参数名列表 const paramNames = getFunctionParamNames(originalMethod); // 执行参数校验 if (!paramNames.includes('executionTime')) { throw new Error(`方法 ${String(methodName)} 缺失必填参数executionTime,禁止使用@performanceDecorator装饰器`); } // 校验通过后原样返回方法描述符,后续扩展性能采集逻辑也可以在这里处理 return descriptor; } } /** * 工具方法:提取函数的参数名列表,自动过滤注释、默认值等干扰内容 */ function getFunctionParamNames(func: Function): string[] { const fnStr = func.toString() // 移除多行注释 .replace(/\/\*[\s\S]*?\*\//g, '') // 移除单行注释 .replace(/\/\/.*$/gm, '') .trim(); // 匹配普通函数、箭头函数的参数段 const paramMatch = fnStr.match(/^(?:function\s*[^(]*\()|(?:^\s*\(?)\s*([^)]*)\)?/m); if (paramMatch?.[1]) { return paramMatch[1].split(',') .map(param => param.trim().split('=')[0].trim()) .filter(Boolean); } return []; }
扩展:编译期提前校验
如果希望在编码阶段就得到参数错误提示,不需要等到运行时才报错,可以补充TS类型校验逻辑,修改装饰器的类型定义即可:
// 定义类型约束:要求方法最后一个参数必须是number类型的executionTime type WithExecutionTime<T extends (...args: any[]) => any> = T extends (...args: infer P) => infer R ? P extends [...rest: any[], executionTime: number] ? T : never : never; function performanceDecorator() { return function <T extends (...args: any[]) => any>(target: any, methodName: string | symbol, descriptor: TypedPropertyDescriptor<T>) { // 原有的运行时校验逻辑保留 const originalMethod = descriptor.value!; const paramNames = getFunctionParamNames(originalMethod); if (!paramNames.includes('executionTime')) { throw new Error(`方法 ${String(methodName)} 缺失必填参数executionTime,禁止使用@performanceDecorator装饰器`); } // 返回带类型约束的描述符,触发TS编译校验 return descriptor as TypedPropertyDescriptor<WithExecutionTime<T>>; } }
修改后没有加executionTime参数的方法在编码阶段就会被TS标红提示类型不匹配。
内容的提问来源于stack exchange,提问作者Ankit Gupta
相关产品推荐
相关产品推荐

