You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript装饰器间通信:实现支持忽略参数的缓存装饰器

实现带参数忽略功能的TypeScript缓存装饰器

核心思路

要让@CachedParamIgnore告知@Cached哪些参数需要忽略,核心是通过参数装饰器记录被标记参数的索引,存储到方法的元数据中,再由方法装饰器读取这些索引,生成缓存Key时跳过对应参数。

具体实现

1. 实现@CachedParamIgnore参数装饰器

这个装饰器负责标记需要忽略的参数,并把参数索引存入目标方法的元数据:

import 'reflect-metadata';

// 定义专属元数据键,用于存储忽略的参数索引
const IGNORED_PARAMS_KEY = Symbol('cached:ignored-params');

export function CachedParamIgnore() {
  return function (target: any, methodName: string | symbol, paramIndex: number) {
    // 获取已有的忽略索引数组,无则初始化空数组
    const ignoredParams = Reflect.getMetadata(IGNORED_PARAMS_KEY, target, methodName) || [];
    ignoredParams.push(paramIndex);
    // 更新元数据
    Reflect.defineMetadata(IGNORED_PARAMS_KEY, ignoredParams, target, methodName);
  };
}

2. 实现@Cached方法装饰器

在这个装饰器里读取元数据中的忽略索引,生成缓存Key时过滤掉对应参数:

export function Cached() {
  return function (target: any, methodName: string | symbol, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    // 缓存容器,键为处理后的参数组合,值为方法返回结果
    const cache = new Map<string, any>();

    descriptor.value = function (...args: any[]) {
      // 获取需要忽略的参数索引
      const ignoredParams = Reflect.getMetadata(IGNORED_PARAMS_KEY, target, methodName) || [];
      // 过滤被标记的参数,生成缓存Key
      const filteredArgs = args.filter((_, index) => !ignoredParams.includes(index));
      const cacheKey = JSON.stringify(filteredArgs);

      // 缓存命中直接返回,否则执行原方法并缓存结果
      if (cache.has(cacheKey)) {
        return cache.get(cacheKey);
      }
      const result = originalMethod.apply(this, args);
      cache.set(cacheKey, result);
      return result;
    };

    return descriptor;
  };
}

3. 使用示例

class BarFoo {
  @Cached()
  doComplexCalc(@CachedParamIgnore() a: number, b: number, c: string) {
    console.log('执行复杂计算');
    return a + b + c.length;
  }
}

const instance = new BarFoo();
instance.doComplexCalc(1, 2, 'test'); // 打印"执行复杂计算",返回5
instance.doComplexCalc(100, 2, 'test'); // 直接返回5,不执行计算(a被忽略,b、c参数一致)
instance.doComplexCalc(1, 3, 'test'); // 打印"执行复杂计算",返回6

注意事项

  • 必须在tsconfig.json中开启编译选项:
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}
  • 如果参数是复杂对象,JSON.stringify可能无法生成唯一Key,可替换为自定义序列化逻辑(比如结合lodash.isEqual和哈希函数)。
  • 上述实现中所有类实例共享同一缓存,若需每个实例独立缓存,可将cache定义在实例对象上,而非装饰器闭包内。

内容的提问来源于stack exchange,提问作者Jeanluca Scaljeri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 14:35:45