Reputation: 951
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?
Upvotes: 4
Views: 2291
Reputation: 8005
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.
Upvotes: 3
Reputation: 8620
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.
Upvotes: 3