Still Hand-Writing setTimeout Promise Wrappers?
Somewhere in your project, there's probably this:
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
It works, sure. But since Node.js 16, there's a built-in version in timers/promises. Just use it directly.
import { setTimeout as sleep } from "node:timers/promises";
The node: prefix explicitly tells the toolchain this is a built-in module, not some package with the same name in node_modules. The as sleep alias is because setTimeout looks awkward—renaming it makes things clearer.
Basic Usage
async function main() {
await sleep(2000);
console.log("Waited 2 seconds");
}
Same effect as the hand-written version, but without an unnecessary utility function.
It Has One More Parameter Than Your Hand-Written Version
setTimeout(delay?: number, value?: T, options?: TimerOptions): Promise<T>
The second parameter value is the value passed along when the promise resolves. Sometimes it's handy (sometimes you'll never use it—just good to know it exists).
The third parameter options includes signal, which works with AbortController to cancel the wait midway. Implementing that in a hand-written version is much more cumbersome.
const controller = new AbortController();
setTimeout(() => controller.abort(), 500);
try {
await sleep(2000, undefined, { signal: controller.signal });
} catch (e) {
console.log("Cancelled");
}
Types
@types/node 18 and above have complete types with proper generics—no need to annotate manually. If you get errors, first check the version; it's likely @types/node is too old. npm update @types/node usually fixes it.
What About Old Projects?
If you come across it, swap it out. No need to open a dedicated PR just for this.