import Reject from './interfaces/promise/reject.interface' import Cancel from './interfaces/promise/cancel.interface' import Resolve from './interfaces/promise/resolve.interface' import CancelHandler from './interfaces/promise/cancel-handler.interface' export default class CancelablePromise { private cancelHandler: CancelHandler = reason => {} private isPending: boolean private promise: Promise isCanceled: boolean constructor(callback: { (resolve: Resolve, reject: Reject, onCancel: Cancel): void ( arg0: (value: any) => void, arg1: (error: any) => void, arg2: (handler: any) => void ): void }) { this.isPending = true this.isCanceled = false this.promise = new Promise((resolve, reject) => { const onResolve = (value?: T | PromiseLike): void => { this.isPending = false resolve(value) } const onReject: Reject = reason => { this.isPending = false reject(reason) } const onCancel = (handler: CancelHandler) => { if (!this.isPending) { throw new Error( 'The `onCancel` handler was attached after the promise settled.' ) } this.cancelHandler = handler } return callback(onResolve, onReject, onCancel) }) } then( onFulfilled?: | ((value: T) => TResult1 | PromiseLike) | undefined | null, onRejected?: | ((reason: any) => TResult2 | PromiseLike) | undefined | null ): Promise { return this.promise.then(onFulfilled, onRejected) } catch( onRejected?: | ((reason: any) => TResult | PromiseLike) | undefined | null ): Promise { return this.promise.catch(onRejected) } cancel(reason?: any) { if (!this.isPending || this.isCanceled) { return } this.cancelHandler(reason) this.isCanceled = true } }