TypeScript实现仅接受简单类型参数的memoize函数类型报错如何解决
问题原因
- TS函数参数存在逆变特性,你定义的
FuncWithSimpleParams参数类型是宽松的简单类型联合数组,你传入的函数参数是明确的更窄的string类型,不符合泛型约束的逆变检查规则,因此触发类型报错。 - 代码存在运行时BUG:你声明
cache为普通对象,却调用了仅Map实例存在的get方法,运行时会直接抛出异常。
修复后完整代码
// 定义允许的简单参数类型集合 type SimpleType = number | string | boolean | null | undefined; // 约束入参函数的参数数组每一项都属于简单类型 type AllowedFunc<P extends SimpleType[], R> = (...args: P) => R; export function memoize<P extends SimpleType[], R>(func: AllowedFunc<P, R>) { // 使用Map作为缓存载体,读写更符合预期 const cache = new Map<string, R>(); return function wrapper(...args: P): R { // 拼接缓存key时逐位转字符串,再用特殊分隔符拼接,避免不同参数组合撞key const cacheKey = args.map(String).join('||'); if (cache.has(cacheKey)) { // 非空断言:已经判断存在,必然能取出值 return cache.get(cacheKey)!; } const result = func(...args); cache.set(cacheKey, result); return result; }; } // 调用测试,无类型报错 memoize(function (first: string, second: string) { return `${first}${second}` })
修复说明
- 调整泛型定义顺序:先声明参数数组泛型
P和返回值泛型R,再约束P的每一项都是简单类型,避开了原写法触发的函数参数逆变检查,同时完整保留了传入函数的参数类型推导 - 修复缓存读写逻辑:改用
Map作为缓存载体,避免普通对象属性名和原型链属性冲突的问题,同时修复了原代码的方法调用错误 - 优化缓存key生成逻辑:用特殊分隔符拼接参数,避免参数本身包含
.时,不同参数组合生成相同key导致缓存混乱的问题
内容的提问来源于stack exchange,提问作者Adrian Adkison
相关产品推荐
相关产品推荐

