Skip to content
GreenSnippets

Debounce with preserved argument types

A debounce function whose returned function keeps the parameter types and exposes cancel() and flush().

TypeScript
function debounce<F extends (...args: never[]) => void>(fn: F, waitMs: number) {
  let timer: ReturnType<typeof setTimeout> | undefined;
  let lastArgs: Parameters<F> | undefined;

  const run = () => {
    timer = undefined;
    if (lastArgs) fn(...lastArgs);
    lastArgs = undefined;
  };

  const debounced = (...args: Parameters<F>) => {
    lastArgs = args;
    clearTimeout(timer);
    timer = setTimeout(run, waitMs);
  };
  debounced.cancel = () => {
    clearTimeout(timer);
    timer = undefined;
    lastArgs = undefined;
  };
  debounced.flush = () => {
    if (timer !== undefined) {
      clearTimeout(timer);
      run();
    }
  };
  return debounced;
}

Example / expected output

Output
const save = debounce((id: number, text: string) => api.save(id, text), 300);
save(1, "draft"); // only the last call within 300 ms runs

How it works

Parameters<F> carries the original argument list through, so callers of the debounced function still get type checking. cancel clears a pending call and flush runs it immediately, which is useful when a component unmounts or a form is submitted.

  • JavaScript Tested

    Run a function only once

    Wrap a function so it executes on the first call and returns the same result afterwards.

  • JavaScript Tested

    Memoize a function

    Cache results by argument so expensive pure functions only run once per distinct input.

  • JavaScript Tested

    Curry a function

    Turn a multi-argument function into one that can be called a few arguments at a time.

  • JavaScript Tested

    Compose and pipe functions

    Chain single-argument functions left-to-right with pipe, or right-to-left with compose.