I'd like to create a QueryPromise that is just a concrete promise with a cancel method. Here's how it would be used:
function runQuery(text: string): QueryPromise {
return new QueryPromise((resolve,reject) => {nativeQuery(resolve)})
}
Here is my first attempt, hopefully pretty understandable:
interface CancellablePromise<T> extends Promise<T> {
cancel: () => void
}
// create the promise my app will use
type QueryPromise = CancellablePromise<string|boolean>
But that's not sufficient.
After a few hours of trial and error I managed to get close, but this seems tedious and anything but DRY.
interface CancellablePromise<T> extends Promise<T> {
cancel: () => void
}
// also need this interface so the variable can be declared
// plus need to redeclare methods to return the new type
interface CancellablePromiseConstructor extends PromiseConstructor {
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): CancellablePromise<T>;
cancel: () => void
}
type QueryPromise = CancellablePromise<string|boolean> // for parameter types
var QueryPromise: CancellablePromiseConstructor = Promise // for the new operator
// some example code to exercise the promise
function runQuery(text: string): QueryPromise {
return new QueryPromise((resolve,reject) => {nativeQuery(resolve)})
}
I feel like I've gone a long way down the wrong road... Does anyone know of a better way to do this?
Promises have settled (hah) and it appears like it will never be possible to cancel a (pending) promise. Instead, there is a cross-platform (Node, Browsers etc) cancellation primitive as part of WHATWG (a standards body that also builds HTML) called AbortController .
Promise cannot be cancelled, it is the process that returns promise must be cancellable. For example, XmlHttpRequest is cancellable as it has an abort method. Fetch api also supports AbortController. signal, that is cancellable.
To force cancel a promise with JavaScript, we use the AbortController constructor. const controller = new AbortController(); const task = new Promise((resolve, reject) => { //... controller. signal.
TypeScript interfaces and types describe contracts. Yours are fine:
interface CancellablePromise<T> extends Promise<T> {
cancel: () => void
}
type QueryPromise = CancellablePromise<string | boolean>
You can then implement a contract as you want. Here is an example:
function runQuery(text: string): QueryPromise {
let rejectCb: (err: Error) => void
let p: Partial<QueryPromise> = new Promise<string | boolean>((resolve, reject) => {
rejectCb = reject
/* ... Here the implementation of the query ... */
});
p.cancel = () => {
/* ... Here the implementation of the aborting ... */
rejectCb(new Error("Canceled"))
}
return p as QueryPromise
}
Notices:
cancel
should reject the promise;Partial<QueryPromise>
in order to add the member cancel
afterward.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With