Home > OS >  How to set types for a function which is as function argument and can have any arguments and any ret
How to set types for a function which is as function argument and can have any arguments and any ret

Time:10-09

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.

Playground link to code

  • Related