I want to write a debounce function with typescript. My code is shown below:
function debounce(fn: Function, time: number): Function {
// ...
}
And then, my eslint
tell me don't use Function
as a type. Below is original text:
Don't use Function
as a type. The Function
type accepts any function-like value.
It provides no type safety when calling the function, which can be a common source of bugs.
It also accepts things like class declarations, which will throw at runtime as they will not be called with new
.
If you are expecting the function to accept certain arguments, you should explicitly define the function shape.
That's the problem, any suggestion?
==================== Some update ==================================
If use javascript, my code will be:
function debounce(fn, time) {
let timer
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => fn(...args), time)
}
}
CodePudding user response:
I recommend you look into TypeScript's utility types, such as Parameters<Type>
and ThisParameterType<Type>
. They're what I used for my TypeScript implementation of a debounce function to make the returned function match the signature of the input function.
As for how I specified the function argument, I used generics like this:
const debounce = function<T extends (...args: any) => any> (fn: T, delay: number) {
CodePudding user response:
Given your implementation, the function returned from debounce()
does not return a useful result; that means we don't care what the return type of the fn
argument is. In this case, I'd probably make debounce()
a generic function with a type parameter A
as a rest tuple corresponding to the arguments to fn
. Like this:
function debounce<A extends any[]>(fn: (...a: A) => void, time: number) {
let timer: number;
return function (...args: A) {
clearTimeout(timer)
timer = setTimeout(() => fn(...args), time)
}
}
The type (...a: A) => void
is a function type expression, meaning "a function whose arguments array is of type A
and which returns void
so its return type will be ignored".
If you inspect the type of debounce()
, it looks like this:
/* function debounce<A extends any[]>(
fn: (...a: A) => void, time: number
): (...args: A) => void */
So it takes a function of type (...a: A) => void
and it returns a function of the same type.
Let's make sure it works:
function log(x: string) {
console.log(x);
}
const debouncedLog = debounce(log, 1000);
debouncedLog("hello");
debouncedLog(100); // error, doesn't accept a number
debouncedLog("there");
// just "there" is logged
You can see that the compiler complains about debouncedLog(100)
because 100
is not assignable to string
, while the other calls work.