/** * A promise that can be resolved or rejected from outside. */ export type ControllablePromise = Promise & { resolve(val: T): void reject(err?: unknown): void } /** * A promise that can be cancelled. */ export type CancellablePromise = Promise & { cancel(): void } /** * The promise was cancelled */ export class PromiseCancelledError extends Error {} /** * Creates a promise that can be resolved or rejected from outside. */ export function createControllablePromise(): ControllablePromise { let _resolve: any let _reject: any const promise = new Promise((resolve, reject) => { _resolve = resolve _reject = reject }) ;(promise as ControllablePromise).resolve = _resolve ;(promise as ControllablePromise).reject = _reject return promise as ControllablePromise } /** * Creates a promise that can be cancelled. * * @param onCancel Callback to call when cancellation is requested */ export function createCancellablePromise( onCancel: () => void ): ControllablePromise & CancellablePromise { const promise = createControllablePromise() ;(promise as unknown as CancellablePromise).cancel = () => { promise.reject(new PromiseCancelledError()) onCancel() } return promise as ControllablePromise & CancellablePromise }