Easy

Cancellable Timeout

Prompt

Create a function called setCancellableTimeout that works like JavaScript's built-in setTimeout, but returns a cancel function instead of a numeric timer ID.

Your function should accept a callback function and a delay time in milliseconds. It should schedule the callback to run after the specified delay. Most importantly, it should return a function that, when called, cancels the pending timeout so the callback never fires.

Playground

Hint 1

Call setTimeout inside your function and store the timer ID it returns. You'll need that ID to cancel the timeout later.

Hint 2

Return a function that calls clearTimeout with the stored timer ID. The returned function forms a closure over the ID, keeping it accessible even after setCancellableTimeout finishes executing.

Hint 3

The built-in setTimeout supports passing extra arguments after the delay, which get forwarded to the callback. You can use rest parameters (...args) to support this in your wrapper too.

Solution

Explanation

This is the timeout counterpart to setCancellableInterval, and it follows the exact same closure pattern. If you've solved one, you've essentially solved the other.

The native setTimeout returns a numeric timer ID, and the only way to cancel a pending timeout is to pass that ID to clearTimeout. The problem is that this forces you to manage the ID yourself, often storing it in an outer variable. This wrapper gives you a cleaner API: instead of an opaque number, you get back a function that knows how to cancel itself.

function setCancellableTimeout(func, delay, ...args) {
const timerId = setTimeout(func, delay, ...args);

return () => {
clearTimeout(timerId);
};
}

The entire mechanism relies on closure. The timerId variable is created inside setCancellableTimeout's scope. When we return the arrow function, that function captures a reference to timerId and keeps it alive. Calling the returned function triggers clearTimeout(timerId), which tells the browser to cancel the scheduled callback.

The ...args rest parameter forwards any additional arguments to the callback through setTimeout. This mirrors how the native setTimeout works:

const cancel = setCancellableTimeout(
(name) => console.log(`Hello, ${name}!`),
1000,
'World'
);

This pattern shows up constantly in UI code. Think of search-as-you-type: you schedule a timeout to fire an API call after the user stops typing, but if they type another character, you cancel the previous timeout and schedule a new one. Having a cancel function makes that kind of logic much more readable than juggling timer IDs.

Like the interval version, you can write a maximally concise variant:

function setCancellableTimeout(...args) {
const timerId = setTimeout(...args);
return () => clearTimeout(timerId);
}

Both approaches are valid in an interview. The explicit-parameter version communicates intent better; the spread version is terser. Pick whichever feels natural and be ready to explain the closure.