我希望高阶函数能够捕获具有不同签名的传递函数的签名参数。
我不知道这是否可行,但这是我的解决方法:
type FuncA = (a: string, b: number) => void
type FuncB = (a: string) => void
type Func = FuncA | FuncB
const a: FuncA = (a: string, b: number) => {
console.log('FuncA')
}
const b: FuncB = (a: string) => {
console.log('FuncB')
}
// My higher order function
const c = (func: Func) => {
// do something here...
return (...args: Parameters<typeof func>) => {
func(...args) // Expected 2 arguments, but got 0 or more. ts(2556). An argument for 'a' was not provided.
}
}
我的高阶函数c
无法传递func
的参数
看来TypeScript无法区分类型Func
的不同可能签名。
有人知道写这种代码的模式吗?
谢谢!
答案 0 :(得分:0)
如果装饰功能可以是任何功能,您都可以:
const c = <T extends (...a: any) => any>(func: T) => {
// do something here...
return (...args: Parameters<typeof func>): ReturnType<T> => {
return func(...args);
}
}
调用它看起来像
c<typeof a>(a)('a', 2)
答案 1 :(得分:0)
这是一个艰难的过程,因为对于一个extend
函数来说,另一个函数并不完全意味着您的想法。
我们希望c
创建的函数要求参数与给定的函数相对应。因此,我们使用generic来描述函数。
const c = <F extends Func>(func: F) => {
return (...args: Parameters<F>) => {
func(...args); // still has error
}
}
在这一点上,我们仍然存在该错误,但是当我们调用c
时,我们会得到一个函数,该函数具有基于给定a
或b
的正确参数。 / p>
const cA = c(a); // type: (a: string, b: number) => void
cA("", 0);
const cB = c(b); // type: (a: string) => void
cB("");
对于错误,它与一个函数扩展另一个函数的含义有关。尝试将F extends Func
更改为F extends FuncA
和F extends FuncB
以查看会发生什么。使用F extends FuncB
时,我们会在c(a)
上看到错误,但是使用F extends FuncA
时,我们不会在c(b)
上看到错误。嗯?
如果您从回调的角度考虑它,那是有道理的。传递一个需要比预期少的参数的函数是可以的,但传递一个需要更多参数的函数不是可以的。但是我们是实现回调的人,因此这给我们带来了问题。如果我们使用不带参数的函数扩展type Func
,则Parameters<F>
中的空数组不足以调用这两种类型。
我们必须使泛型依赖于参数。
type AP = Parameters<FuncA> // type: [a: string, b: number]
type BP = Parameters<FuncB> // type: [a: string]
type Args = AP | BP;
const c = <A extends Args>(func: (...args: A) => void) => {
return (...args: A) => {
func(...args) // no error
}
}