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

如何为TypeScript内存缓存函数添加正确泛型类型以实现参数校验

解决TypeScript缓存函数的泛型类型检查问题

修改后的代码

type AnyFunc = (...args: any[]) => any;

// 调整MemCache类型,将泛型T移到调用签名上
type MemCache = {
  <T extends AnyFunc>(fn: T, ...args: Parameters<T>): ReturnType<T>;
  debug: () => void;
};

function makeCache(): MemCache {
  const cache: Record<string, any> = {};

  // 内部函数使用泛型调用签名,与MemCache匹配
  function queryCache<T extends AnyFunc>(fn: T, ...args: Parameters<T>): ReturnType<T> {
    // 这里可以添加缓存逻辑,示例中保留原执行逻辑
    const key = `${fn.name}:${JSON.stringify(args)}`;
    if (!cache[key]) {
      cache[key] = fn(...args);
    }
    return cache[key];
  }

  queryCache.debug = () => {
    console.log(cache);
  };

  return queryCache;
}

const memcache = makeCache();

const fn = (num: number, str: string) => 'hello';

// @ts-expect-error 参数缺失,编译器会报错
const res = memcache(fn);

// @ts-expect-error res是string类型,没有then方法,编译器会报错
res.then();

问题原因分析

原代码的核心问题在于泛型参数的绑定时机错误:

  • 原makeCache<T extends AnyFunc>()的泛型T在调用makeCache()时就被推断为最宽泛的AnyFunc,导致返回的MemCache<T>调用签名的参数被放宽为any[],无法对传入的目标函数参数做类型检查。
  • 调整后的MemCache将泛型T移到了调用签名上,意味着每次调用memcache时,TypeScript会根据传入的目标函数fn实时推断T的类型,从而严格检查参数是否匹配目标函数的要求。

关键修改点

  1. MemCache类型重构:将泛型从类型级别下移到调用签名级别,让类型推断延迟到函数调用时发生。
  2. 移除makeCache的泛型参数:因为缓存实例不需要预先绑定某个特定函数类型,而是要支持任意函数的缓存。
  3. 缓存对象类型优化:给cache添加Record<string, any>类型,避免隐式any警告。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:34:58