这个函数类型:
type FuncWithSimpleParams = (...args: (number | string | boolean | null | undefined)[])
=> any;
声明一个可以使用任何这些参数调用的函数。但是你传给它一个只能接受string 参数的函数。
“但是,Alex”,你是说“T extends FuncWithSimpleParams 应该允许这样做,对吧?”
嗯,不。
type Test = // This is `false`
((a: 1) => void) extends ((a: 1 | 2) => void)
? true
: false
所以函数参数不能以这种方式扩展。
您确实有错误的泛型。相反,您希望将函数的参数作为泛型类型,这样您就不必担心扩展函数类型的复杂语义。
例如:
type SimpleType = number | string | boolean | null | undefined
type FuncWithSimpleParams<T extends SimpleType> = (...args: T[]) => any;
现在FuncWithSimpleParams 有一个泛型。这意味着结果将只允许 SimpleType 的子集作为参数,无论是通用参数的子集。
现在memoize 变为:
export function memoize<T extends SimpleType>(func: FuncWithSimpleParams<T>) {
以及所有works as expected on this playground
此外,现在您完全摆脱了ArgTypes(无论如何只是Parameters<T>),而只需使用T[],因为您知道参数类型而无需显式询问函数。
export function memoize<T extends SimpleType>(func: FuncWithSimpleParams<T>) {
const cache = {}
return function wrapper(...args: T[]) { // just T[] now
const cacheKey = args.join('.');
const cacheHit = cache.get(cacheKey);
if (cacheHit) {
return cacheHit;
}
const result = func(...args);
cache[cacheKey] = result;
return result;
};
}
当你得到正确的答案时,一切似乎都变得简单了,真是令人惊讶。
这几乎可行。我的示例应该使用不同类型的参数。如果将“第二个”参数更改为数字。你得到了我所指的错误
如果你想允许任意数量的不同类型的参数,那么你的泛型需要是一个数组类型,这允许它把参数推断为一个已知长度的元组类型,其中每个索引都有一个特定的类型。
type SimpleType = number | string | boolean | null | undefined
type FuncWithSimpleParams<T extends SimpleType[]> = (...args: T)
=> any;
export function memoize<T extends SimpleType[]>(func: FuncWithSimpleParams<T>) {
const cache = {}
return function wrapper(...args: T) {
const cacheKey = args.join('.');
const cacheHit = cache.get(cacheKey);
if (cacheHit) {
return cacheHit;
}
const result = func(...args);
cache[cacheKey] = result;
return result;
};
}
memoize(function (first: string, second: number) {
return `${first}${second}`
})
Playground