diff --git a/readme.md b/readme.md index bf148e1..df37cd8 100644 --- a/readme.md +++ b/readme.md @@ -63,7 +63,8 @@ Concurrency limit. ##### timeout -Type: `number` +Type: `number`\ +Default: `undefined` (i.e. no timeout is enforced) Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses if they haven't already. @@ -72,7 +73,9 @@ Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses Type: `boolean`\ Default: `false` -Whether or not a timeout is considered an exception. +Whether or not a timeout is considered an exception. When `false`, promises will resolve without a value on timeout. + +Obviously, this option only has an effect when `timeout` is defined. ##### autoStart diff --git a/source/index.ts b/source/index.ts index faf2c9e..852d7c5 100644 --- a/source/index.ts +++ b/source/index.ts @@ -2,7 +2,7 @@ import {EventEmitter} from 'eventemitter3'; import pTimeout, {TimeoutError} from 'p-timeout'; import {type Queue, type RunFunction} from './queue.js'; import PriorityQueue from './priority-queue.js'; -import {type QueueAddOptions, type Options, type TaskOptions} from './options.js'; +import {type QueueAddOptions, type Options, type TaskOptions, type WithoutTimeout, type WithoutTimeoutThrow, type WithTimeoutThrow} from './options.js'; type Task = | ((options: TaskOptions) => PromiseLike) @@ -231,15 +231,32 @@ export default class PQueue(function_: Task, options: {throwOnTimeout: true} & Exclude): Promise; - async add(function_: Task, options?: Partial): Promise; - async add(function_: Task, options: Partial = {}): Promise { + async add( + function_: Task, + options?: WithoutTimeout> + ): Promise; + async add( + function_: Task, + options: WithTimeoutThrow> + ): Promise; + async add( + function_: Task, + options: WithoutTimeoutThrow> + ): Promise; + async add( + function_: Task, + options: Partial = {}, + ): Promise { options = { timeout: this.timeout, throwOnTimeout: this.#throwOnTimeout, ...options, }; + if (!options.timeout && options.throwOnTimeout) { + console.warn('You specified `throwOnTimeout=true` without defining `timeout`.'); + } + return new Promise((resolve, reject) => { this.#queue.enqueue(async () => { this.#pending++; @@ -287,15 +304,19 @@ export default class PQueue( functions: ReadonlyArray>, - options?: {throwOnTimeout: true} & Partial>, + options?: WithoutTimeout>, + ): Promise; + async addAll( + functions: ReadonlyArray>, + options: WithTimeoutThrow> ): Promise; async addAll( functions: ReadonlyArray>, - options?: Partial, + options: WithoutTimeoutThrow>, ): Promise>; async addAll( functions: ReadonlyArray>, - options?: Partial, + options: Partial = {}, ): Promise> { return Promise.all(functions.map(async function_ => this.add(function_, options))); } diff --git a/source/options.ts b/source/options.ts index 8e8bf7b..c536e62 100644 --- a/source/options.ts +++ b/source/options.ts @@ -109,3 +109,23 @@ export type TaskOptions = { */ readonly signal?: AbortSignal; }; + +/** +Helper type to target the case where timeout=number. +*/ +export type WithTimeout = Options & {timeout: number}; + +/** +Helper type to target the case where timeout=undefined. +*/ +export type WithoutTimeout = Omit | {timeout: undefined}; + +/** +Helper type to target the case where timeout=number and throwOnTimeout=true. +*/ +export type WithTimeoutThrow = WithTimeout & {throwOnTimeout: true}; + +/** +Helper type to target the case where timeout=number and throwOnTimeout=false/undefined. +*/ +export type WithoutTimeoutThrow = WithTimeout & {throwOnTimeout?: false}; diff --git a/test-d/index.test-d.ts b/test-d/index.test-d.ts index 67641a7..ee129ba 100644 --- a/test-d/index.test-d.ts +++ b/test-d/index.test-d.ts @@ -3,5 +3,14 @@ import PQueue from '../source/index.js'; const queue = new PQueue(); -expectType>(queue.add(async () => '🦄')); +expectType>(queue.add(async () => '🦄')); +expectType>(queue.add(async () => '🦄', {})); +expectType>(queue.add(async () => '🦄', {throwOnTimeout: undefined})); +expectType>(queue.add(async () => '🦄', {throwOnTimeout: false})); expectType>(queue.add(async () => '🦄', {throwOnTimeout: true})); +expectType>(queue.add(async () => '🦄', {timeout: undefined})); +expectType>(queue.add(async () => '🦄', {timeout: 1, throwOnTimeout: true})); +expectType>(queue.add(async () => '🦄', {timeout: 1})); +expectType>(queue.add(async () => '🦄', {timeout: 1, throwOnTimeout: undefined})); +expectType>(queue.add(async () => '🦄', {timeout: 1, throwOnTimeout: false})); +expectType>(queue.add(async () => '🦄', {priority: 1}));