简体   繁体   中英

async/await in a class method called “then”

I created a class that has a "then" method. This class is unrelated to the Promise type; the "then" method has a different purpose and doesn't return a promise. I am trying to write an async/await function in Typescript 2.1.4 that awaits and returns an instance of this class, but the Typescript server in VS Code is giving me errors. If I rename the method to something other than "then", the errors go away.

Example code with errors:

class MyClass {
    then(): number {
        // this method isn't related to Promise.then
        return 2 + 2;
    }
}

// three errors below go away when "then" is renamed

// [ts] An async function or method must have a valid awaitable return type.
async function my_async(): Promise<MyClass> {
    let a: Promise<MyClass> = Promise.resolve(new MyClass());

    // [ts] Operand for 'await' does not have a valid callable 'then' member.
    let b: MyClass = await a;

    // [ts] Return expression in async function does not have a valid callable 'then' member.
    return b;
}

Can someone explain why using promises with an object that has its own "then" method is not allowed, or a work around?

Promises are defined as objects that have a method called .then . They are not defined, for instance, as "the module returned by require('bluebird/promise') ".

Part of what makes this important is that when a promise library is resolving a promise, it is not meant to offer up the final result inside of a call to .then if that result is a promise itself. For instance:

function myFn() {
  // doPromise1 will eventually give us `1`.
  return doPromise1().then(x => {
    // doPromise2 will eventually give us `2`.
    return doPromise2();
  });
}

Calling this function and calling .then on the result won't return the promise I got inside of doPromise2() . It will return 2 - so it will wait until both promises finish, and give that final value.

This is different from if I had returned 3 inside of then . It would see that the result is not a promise, and offer up that as the final value. However, the crux of the issue is how it knows that that is not a promise. It doesn't do typechecking, like if p instanceof Promise because there are too many Promise definitions and polyfills in various libraries, and they're meant to work together. Instead, they check something generic that should look like this: if (typeof p.then === 'function') .

That check is returning true for your class, and this causes it to think your value is a Promise itself. It runs it, hoping to get back another promise object, but gets a number and fails.

Your then method is related to the Promise API - from the JavaScript ducktyping point of view, your class is a thenable see the spec , specifically this step

...
Let then be Get(resolution, "then").
...

If your promise resolves to an object that has a then function, then it has a special meaning - it's a thenable . You cannot yield result objects that have a then function and not have them treated by the Promise resolution algorithm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM