Typescript: subclass/extend of Promise: does not refer to a Promise-compatible constructor value
Asked Answered
S

2

10

I'm trying to cancel my async method call in Typescript.

To do this, I have created a new Promise type, which inherits from Promise:

class CancelablePromise<T> extends Promise<T>{

    private cancelMethod: () => void;
    constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void, cancelMethod: () => void) {
        super(executor);
        this.cancelMethod = cancelMethod;
    }

    //cancel the operation
    public cancel() {
        if (this.cancelMethod) {
            this.cancelMethod();
        }
    }
}

But when I'm trying to use it:

async postFileAjax<T>(file: File): CancelablePromise<T> { ... }

I get the error:

Error Build:Type 'typeof CancelablePromise' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.

If I using the type declaration and return the CancelablePromise, like this then it compiles:

async postFileAjax<T>(file: File): Promise<T>  { 
     ...
     return CancelablePromise(...);
}

What am I doing wrong? I see that in ES6 you could subclass the Promise (see stackoverflow question), so I would expect it also in TypeScript.

Using Typescript 2.1 and targeting es5

Starobin answered 10/4, 2017 at 15:27 Comment(7)
You can't extend built-in types unless you target es6 (or above)Shutt
if you have a reference for that, then that's the accepted answer ;)Starobin
Try this one: Extending from Error doesn't work when emitting ES5Shutt
I split the compile and runtime error. Compile error has been solved, now runtime error: #43420675Starobin
Again, you cannot simply extend native types when targeting es5. Notice that when you target es6 then the resulting code is different, it uses es6 classes which makes the inheritance work.Shutt
What you should probably do is to implement PromiseLike instead of extending PromiseShutt
Then i am missing methods? Any way, I think this compilation issue has been solved (see my own answer).Starobin
S
15

The error message wasn't fully clear to me at first, but the signature of the constructor should be completely the same as the constructor of Promise.

I've removed the cancelMethod from the constructor and will set it later. This works:

class CancelablePromise<T> extends Promise<T>{

    public cancelMethod: () => void;
    constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {
        super(executor);

    }

    //cancel the operation
    public cancel() {
        if (this.cancelMethod) {
            this.cancelMethod();
        }
    }
}

and call:

async postFileAjax<T>(file: File): CancelablePromise <T> { 

    var promiseFunc = (resolve) => { resolve() };
    var promise = new CancelablePromise<T>(promiseFunc);
    promise.cancelMethod = () => { console.log("cancel!") };

    return promise;
}
Starobin answered 14/4, 2017 at 22:25 Comment(0)
I
0

Instead of copy-pasting types from constructor parameters it's better to use utility type ConstructorParameters + typeof:

class MyPromise<T> extends Promise<T> {

  constructor(...args: ConstructorParameters<typeof Promise<T>>) {
    super(...args);
  }

}

Adding argument is a bit tricky

class MyPromise<T> extends Promise<T> {

  constructor(...args: [...ConstructorParameters<typeof Promise<T>>, () => void]) {
    const [executor, cancel] = args
    super(executor);

    this.cancel = cancel;
  }

}
Impolicy answered 28/3, 2023 at 10:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.