How to Debounce a Function

A recipe for creating a debounce helper function in TypeScript, which delays running a function until a certain amount of time has passed without it being called.

When you have an event that fires many times in a row (like a search input, or a window resize), you often don’t want to run your code every single time. It’s much more efficient to wait until the event has stopped for a moment.

This is called “debouncing”, and it’s a very common pattern.

Here is a classic debounce function. It takes a function and a delay time, and returns a new, debounced version of that function.

TypeScript
function debounce(func: (...args: any[]) => any, wait: number) {
    let timeout: number | undefined;

    return function (this: any, ...args: any[]) {
        const context = this;
        clearTimeout(timeout);
        timeout = window.setTimeout(() => {
            func.apply(context, args);
        }, wait);
    };
}

How it works:

  1. let timeout: number | undefined;: A variable is kept in memory to store the timer ID from setTimeout.
  2. return function(...): The debounce function returns a new function that you will use instead of your original one. This new function is what gets called every time the event fires.
  3. clearTimeout(timeout): Each time the returned function is called, it first clears the previous timer. This is the key to the whole thing. If the user is still typing, the old timer gets cancelled before it can run.
  4. timeout = window.setTimeout(...): A new timer is set. If the wait time (e.g 500ms) passes without another call clearing it, the original function (func) will finally be executed.

Use Case: A Debounced Search Input

Here is how you would use it with the input event on a search field.

TypeScript
const searchInput = document.querySelector<HTMLInputElement>("#search-input");

if (searchInput) {
    const delay = 500;

    const handleInput = (event: Event) => {
        const target = event.target as HTMLInputElement;
        console.log("Debounced value:", target.value);
    };

    // Wrap the handler in the debounce function
    searchInput.addEventListener("input", debounce(handleInput, delay));
}

Now, the handleInput function will only run 500ms after the user stops typing.

Other recipes in Functions