Abort Signal Timeout Wrapper
A typed helper that links an AbortSignal to a deadline so in-flight requests are cancelled deterministically and listeners never leak.
Code
export interface DeadlineHandle {
readonly signal: AbortSignal;
cleanup(): void;
}
export function withDeadline(timeoutMs: number, parent?: AbortSignal): DeadlineHandle {
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
throw new RangeError("timeoutMs must be a positive number");
}
const controller = new AbortController();
if (parent?.aborted) {
controller.abort(parent.reason);
} else if (parent) {
parent.addEventListener("abort", () => controller.abort(parent.reason), { once: true });
}
const timer: ReturnType<typeof setTimeout> = setTimeout(() => {
controller.abort(new Error(`deadline exceeded after ${timeoutMs}ms`));
}, timeoutMs);
// unref is a Node extension absent in browser typings
const maybeUnref = timer as unknown as { unref?: () => void };
if (typeof maybeUnref.unref === "function") maybeUnref.unref();
return {
signal: controller.signal,
cleanup() {
clearTimeout(timer);
controller.abort(new Error("deadline cancelled"));
},
};
}Report a problem with this exampleOpens a pre-filled issue on GitHub.