I'm trying to strongly type a function (F1) that is passed to another function (F2). F1 has a dynamic amount of parameters so I cannot define any specific type.
The function/hook I'm working on:
export function useDebounceVoidFunction(func: (...params: any[]) => void, timeout: number): (...params: any[]) => void { // F2
let timer: MutableRefObject<NodeJS.Timeout | undefined> = useRef();
const debouncedFunction = useCallback((...params: any[]) => { // F1
clearTimeout(timer.current);
timer.current = setTimeout(() => {
func(...params);
}, timeout);
}, [func, timeout])
return debouncedFunction; // F1
}
This kind of works... but the parameters in F1 are now any. This mean I could supply a function with 2 parameters and then use the F1 with as many parameters as I want.
I tried using the Wildcard type (useDebounceVoidFunction<T>(func: (...params: T[]) ...
but that doesn't work. I think T
at that time is of type unknown
.
Any suggestions on how I could solve this? Couldn't find any post that resolved my issue.
EDIT1: Added small playground and trying to use Parameter Playground
Your function needs to be generic in the tuple type corresponding to the function's parameter list. You can give a function a rest parameter of such a generic type:
function useDebounceVoidFunction<A extends any[]>
(func: (...params: A) => void, timeout: number): (...params: A) => void {
// let timer: MutableRefObject<NodeJS.Timeout | undefined> = useRef();
return (...params: A) => {
func(...params);
};
}
Here, A
is a generic type parameter which has been constrained to an arraylike type (A for Arguments). And both the func
callback and the return type have a params
rest argument of type A
.
When you call useDebounceVoidFunction()
, the compiler will infer a tuple type for A
corresponding to the ordered list of parameter types to the func
argument:
function someFunc(number: number, string: string) {
console.log(number.toFixed(2), string.toUpperCase())
}
function coolStuff() {
const debouncedFunction = useDebounceVoidFunction(someFunc, 200);
debouncedFunction(Math.PI, "abc") // "3.14", "ABC"
}