如何为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的类型,从而严格检查参数是否匹配目标函数的要求。
关键修改点
- MemCache类型重构:将泛型从类型级别下移到调用签名级别,让类型推断延迟到函数调用时发生。
- 移除makeCache的泛型参数:因为缓存实例不需要预先绑定某个特定函数类型,而是要支持任意函数的缓存。
- 缓存对象类型优化:给
cache添加Record<string, any>类型,避免隐式any警告。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

