export type Debounced = ((...args: Args) => void) & { flush: () => void; cancel: () => void; }; export function debounce( fn: (...args: Args) => void, waitMs: number ): Debounced { let timer: ReturnType | null = null; let pendingArgs: Args | null = null; const debounced = (...args: Args): void => { pendingArgs = args; if (timer !== null) clearTimeout(timer); timer = setTimeout(() => { timer = null; const a = pendingArgs!; pendingArgs = null; fn(...a); }, waitMs); }; debounced.flush = (): void => { if (timer === null) return; clearTimeout(timer); timer = null; const a = pendingArgs!; pendingArgs = null; fn(...a); }; debounced.cancel = (): void => { if (timer !== null) clearTimeout(timer); timer = null; pendingArgs = null; }; return debounced; }