Typescript debounce function not calling function passed as parameter

11,573

Solution 1

How do you use your debounce function? I prepare fiddle, you can check working solution here

function debounce<Params extends any[]>(
  func: (...args: Params) => any,
  timeout: number,
): (...args: Params) => void {
  let timer: NodeJS.Timeout
  return (...args: Params) => {
    clearTimeout(timer)
    timer = setTimeout(() => {
      func(...args)
    }, timeout)
  }
}

function test(message) {
  alert(message);
}

const debouncedTest = debounce(test, 2000);

debouncedTest('message');

Well, it's not typescript troubles

Solution 2

This is intended as a supplement to Saveli Tomac's excellent answer.

In the comments I said I didn't think that implementation was particularly good. In particular it has two problems:

  1. It doesn't have an immediate option. Most debounce implementations in the wild (including the one you linked in your question) have this.
  2. The returned function ignores the this value.

Here's an example that fixes these:

const debounce = (n: number, fn: (...params: any[]) => any, immed: boolean = false) => {
  let timer: number | undefined = undefined;
  return function (this: any, ...args: any[]) {
    if (timer === undefined && immed) {
      fn.apply(this, args);
    }
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), n);
    return timer;
  }
};

Typescript Playground

Share:
11,573

Related videos on Youtube

Lucas Meine
Author by

Lucas Meine

Always inventing, improving and creating. I'm a software engineer, Microsoft certified professional and casual StackOverflow user that likes to answer PHP and jquery questions because I miss the old times. Feel free to add me on LinkedIn :) I also host Meine's Rock Bar where I talk about a lot of stuff, including software development How to write a good answer to a question How to create a Minimal, Reproducible Example

Updated on June 04, 2022

Comments

  • Lucas Meine
    Lucas Meine almost 2 years

    I'm trying to write a debounce function with typescript.

    I found an example of it in here. Code follows:

    export function debounce<Params extends any[]>(
      func: (...args: Params) => any,
      timeout: number,
    ): (...args: Params) => void {
      let timer: NodeJS.Timeout
      return (...args: Params) => {
        clearTimeout(timer)
        timer = setTimeout(() => {
          func(...args)
        }, timeout)
      }
    }
    

    Problem is:

    • Function passed as a parameter is not getting called after the specified timeout
    • I can't use lodash or any other external library because I'm trying to avoid adding new dependencies to this project.

    Thanks.

    • Jared Smith
      Jared Smith over 4 years
      @Fluffremovalservice I think it works well enough for what it is (see the answer below), but I'm used to debounce having an immediate option, and those typings look...like the simplest thing that could possibly work rather than something that would actually be a production implementation.
  • Lucas Meine
    Lucas Meine over 4 years
    Actually, I'm getting Type 'Timeout' is not assignable to type 'number' with your example.
  • svltmccc
    svltmccc over 4 years
    @Fluffremovalservice setTimeout from browser returns number (timeout id), but you call it from nodejs. You can change type for timer to NodeJS.Timeout | undefined
  • Lucas Meine
    Lucas Meine over 4 years
    Tried it, and got Type 'Timeout' is not assignable to type 'number' in the clearTimeout(timer) line. Am I still missing something?
  • Jared Smith
    Jared Smith over 4 years
    @Fluffremovalservice I'm not getting error in the playground, see the updated link. What version of Typescript?
  • svltmccc
    svltmccc over 4 years
    @Fluffremovalservice try call global.clearTimeout instead of clearTimeout
  • svltmccc
    svltmccc over 4 years
    @JaredSmith you run your code in browser environment and it's normal behaviour