Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method

An errors blows up when using the typings for the the Google Auth2 API - @types/gapi.auth2. The compiler throws an error 1062 if I create a promise that resolves with the gapi.auth2.GoogleAuth type.

Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method.

The typings have this little quirk:

class GoogleAuth {
    ...
    /**
     * Calls the onInit function when the GoogleAuth object is fully initialized, or calls the onFailure function if
     * initialization fails.
     */
    then(onInit: (googleAuth: GoogleAuth) => any, onFailure?: (reason: {error: string, details: string}) => any): any;
    ...
}

The code in use is something like this:

async function getGapi() {
    return new Promise<gapi.auth2.GoogleAuth>(resolve => {
        ...
    });
}

It doesn't matter whatever is inside the promise scope, as soon as it has that GoogleAuth type - it's upset.

The problem is definitely related to the typings and it's probably easy to create a wrapper or ignore the error entirely. The GoogleAuth object is 'thennable' but why should that cause any problem? Is there a circular reference or something?

What's more troubling is there is very little on the 1062 error. I haven't yet resorted to reading the compiler code, but so far I can't figure out what it's trying to tell me.


Solution 1:

Edit: Answering my own question.

Google's documentation explicity says this:

Warning: do not call Promise.resolve() and similar with the result of gapi.auth2.init(). As the GoogleAuth object returned implements the then() method that resolves with itself, it will create an infinite recursion.

This means there will be trouble whether we're using Typescript or even plain Javascript.

So here Typescript is protecting the user from an infinite recursion. Whether or not that is it's intention, I don't know. The wording seems to suggest it's issue is entirely a typing problem or limitation of the compiler. But it's actually doing an important job.

TL;DR: The promise result is another promise which returns itself. The compiler error is guarding against infinite recursions.

Solution 2:

You just need to omit then from the type.

async function getGapi() {
  return new Promise<Omit<gapi.auth2.GoogleAuth, "then">>(resolve => {

  });
}

Solution 3:

This is the way I found to circumvent this error

private async loadGapiAuth() {
  await new Promise((resolve) => gapi.load('client:auth2', resolve));
  await new Promise((resolve) => gapi.auth2.init(GAPI_CONFIG).then(resolve));
}

then I can do this:

await this.loadGapiAuth();
const auth = gapi.auth2.getAuthInstance();