-
-
Save ca0v/73a31f57b397606c9813472f7493a940 to your computer and use it in GitHub Desktop.
// ts 3.6x | |
function debounce<T extends Function>(cb: T, wait = 20) { | |
let h = 0; | |
let callable = (...args: any) => { | |
clearTimeout(h); | |
h = setTimeout(() => cb(...args), wait); | |
}; | |
return <T>(<any>callable); | |
} | |
// usage | |
let f = debounce((a: string, b: number, c?: number) => console.log(a.length + b + c || 0)); | |
f("hi", 1, 1); | |
f("world", 1); |
Still doesn't work:
compared to:
I think typescript can't infer function say‘ this, so try this: function say(this: {name: string,skeak: any}),
What about this ?
export function debounce<T extends (...args: any[]) => any>(
this: any,
fn: T,
wait: number
): (...args: Parameters<T>) => void {
let timer: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
if (timer) {
clearTimeout(timer); // clear any pre-existing timer
}
const context: any = this; // get the current context
timer = setTimeout(() => {
fn.apply(context, args); // call the function if time expires
}, wait);
};
}
worked for me this one
export function debounce<T extends (...args: any[]) => any>(cb: T, wait: number) {
let h: any;
const callable = (...args: any) => {
clearTimeout(h);
h = setTimeout(() => cb(...args), wait);
};
return <T>(<any>callable);
}
I updated mine to use unknown
instead of any
because otherwise TS complains even though it doesn't matter in this particular case since we're not reassigning args <T extends (...args: unknown[]) => unknown>
.
Another version,
- it respects the types (parameters and return type) of the function to be debounced
- it was made to be used for debouncing functions that returns something (and avoids side-effects). Result is wrapped in a promise. Consequently you'll have to
await
the debounced function.
The trick here (TS >=v4.6), is the generic <T extends (...args: Parameters<T>) => ReturnType<T>>
:
export function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>(
callback: T,
delay: number
) {
let timer: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
const p = new Promise<ReturnType<T> | Error>((resolve, reject) => {
clearTimeout(timer);
timer = setTimeout(() => {
try {
let output = callback(...args);
resolve(output);
} catch (err) {
if (err instanceof Error) {
reject(err);
}
reject(new Error(`An error has occurred:${err}`));
}
}, delay);
});
return p;
};
}
The correct type for
timeout
isReturnType<typeof setTimeout>
notnumber
The return value is a positive integer
which identifies the timer created by the call to setTimeout(). In the browser correct call is window?.setTimeout()
.
https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#return_value
Still no solution that solves my context issue
function debounce<F extends (...args: Parameters<F>) => ReturnType<F>>(
func: F,
waitFor: number,
): (...args: Parameters<F>) => void {
let timeout: ReturnType<typeof setTimeout>;
return (...args: Parameters<F>): void => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), waitFor);
};
}
const person = {
name: 'Jack',
speak: function say(sec:number){
debounce(()=>console.log(`My name is ${this.name} , debounced ${sec}`),sec)();
}
}
person.speak(3_000);
debounce(()=>console.log('hehe'),100)();
debounce(()=>console.log('hehe 1_000'),1_000)();
person.speak(4_000);
not sure if this solution addresses the issue but works
You create a new function every time, therefore person.speak is not debounced
@sylvainpolletvillard I landed here by chance and your initial example works fine for me when I simply ignore the Typescript error commenting the lines before 'this' - not sure if that is a valid solution for you though:
// @ts-expect-error: ignore
Sure, ignoring the error works to fix the error
debounce = <F extends (...args: Parameters<F>) => ReturnType<F>>( func: F, waitFor: number, ) => { let timeout: NodeJS.Timeout const debounced = (...args: Parameters<F>) => { clearTimeout(timeout) timeout = setTimeout(() => func(...args), waitFor) } return debounced }
The timeout type should be ReturnType<typeof setTimeout>
this
derives from the function being called, not the function parameter.this
, so convert it to a function.