declare const setTimeout: (fn: () => void, ms: number) => unknown;
declare const clearTimeout: (timer: unknown) => void;
export type ThrottledFunction<TArgs extends any[]> = {
* Checks if there is any invocation throttled
* Call the throttled function immediately, ignoring any throttling
* that may be in effect. After, a new throttled call will be allowed
* after the interval has passed.
* const logMessage = (message: string) => {
* console.log(`Message: ${message}`)
* const throttledLog = throttle({ interval: 1000 }, logMessage)
* throttledLog('First call') // Logs immediately
* throttledLog('Throttled') // Doesn't log (throttled)
* // Force a log, bypassing the throttle
* throttledLog.trigger('Forced log') // Logs immediately
* // Check if it's still throttled
* throttledLog.isThrottled() // => true
trigger(...args: TArgs): void;
* Given an interval and a function returns a new function that will
* only call the source function if interval milliseconds have passed
* since the last invocation.
* const sup = throttle({ interval: 1000 }, () => {
* setTimeout(() => sup(), 500) // => no logs
* setTimeout(() => sup(), 1000) // => logs "sup"
export function throttle<TArgs extends any[]>(
{ interval, trailing }: { interval: number; trailing?: boolean },
func: (...args: TArgs) => any,
): ThrottledFunction<TArgs> {
let trailingArgs: TArgs | undefined;
const throttled: ThrottledFunction<TArgs> = (...args: TArgs) => {
const isThrottled = () => Date.now() - lastCalled < interval;
throttled.isThrottled = isThrottled;
const trigger = (throttled.trigger = (...args: TArgs) => {
trailingArgs = undefined;
() => trailingArgs && trigger(...trailingArgs),