【问题标题】:Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method类型在其自己的“then”方法的实现回调中直接或间接引用
【发布时间】:2022-01-22 07:55:32
【问题描述】:

使用 Google Auth2 API - @types/gapi.auth2 的类型时会出现错误。如果我创建一个使用 gapi.auth2.GoogleAuth 类型解析的承诺,编译器会抛出错误 1062

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

打字有这个小怪癖:

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;
    ...
}

使用的代码是这样的:

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

promise 范围内的任何内容都无关紧要,只要它具有 GoogleAuth 类型 - 它就会不高兴。

问题肯定与类型有关,创建包装器或完全忽略错误可能很容易。 GoogleAuth 对象是“thennable”,但为什么会导致任何问题?有没有循环引用什么的?

更令人不安的是1062错误很少。我还没有求助于阅读编译器代码,但到目前为止我无法弄清楚它试图告诉我什么。

【问题讨论】:

  • 我在ember-typings repo 中发现ember-data 分型报告的类似问题。他们选择修改他们的打字。
  • 那么这是否表明 Typescript 本身存在问题或 auth2 类型存在问题?它作为普通的 Javascript 代码工作得非常好,所以我建议这是一个 Typescript 问题。
  • 有趣。当你说它在javascript中工作时,这是否意味着onInit回调在GoogleAuth.then()解析时接收到实际上具有then()方法的googleAuth对象?这会很奇怪,因为 promise 保证会解析为不是 promise 的东西。
  • 不,你是对的,我已经假设了一些东西。这表明我们根本不能在 Promise 中使用 GoogleAuth 对象——即使在 javascript 中也是如此。 developers.google.com/identity/sign-in/web/…

标签: typescript


【解决方案1】:

编辑:回答我自己的问题。

Google 的文档明确表示:

警告:不要调用Promise.resolve() 和类似的结果 gapi.auth2.init()。由于返回的 GoogleAuth 对象实现了then() 自己解决的方法,它会创建一个无限递归。

这意味着无论我们使用 Typescript 还是纯 Javascript 都会有问题。

因此,Typescript 在这里保护用户免受无限递归。这是否是它的意图,我不知道。措辞似乎表明它的问题完全是编译器的打字问题或限制。但它实际上在做一项重要的工作。

TL;DR:promise 结果是另一个返回自身的promise。编译器错误是防止无限递归。

【讨论】:

  • 注意:文档中的警告必须是过时的。我刚刚对其进行了测试,then() 方法使用不包含其自己的 then() 方法的不同对象解析。所以没有无限递归。现在的问题只是打字稿类型不正确。
【解决方案2】:

您只需在类型中省略 then

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

  });
}

【讨论】:

  • 是的,虽然这是一个巧妙的解决方法并且让编译器很高兴,但我认为 Typescript 在这里做的是正确的事情。请参阅我接受的答案。
  • 是的,但我的回答更多是针对您的问题的标题。我在处理 gsap 库的定义时提出了该解决方案。 then 方法在完成时被取消,这是我使它工作的唯一方法。 github.com/greensock/GSAP/blob/…
  • 这很有趣。谁在履行时应用 null?它是 JS 原生的东西还是图书馆作者的厚颜无耻的修复?如果是后者,则意味着您的答案不是完整的解决方案,并且还必须保证删除 then 方法。
  • 这是库作者的修复,但修复保证 thenPromise.resolve() 和类似的属性一起使用时将被清空。所以是的,我的解决方案对于 Google Auth 2 API 库可能不正确,但对于 gsap 库是正确的。
【解决方案3】:

这是我发现的绕过这个错误的方法

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

那么我可以这样做:

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

【讨论】:

    【解决方案4】:

    将 Promise 与任何具有自己的 then() 方法的对象一起使用是很危险的。请参阅@gwilz 答案。你会陷入无限循环!

    一种解决方法是实际删除then() 方法:

    async function getGapi() {
      return new Promise<Omit<gapi.auth2.GoogleAuth, "then">>(resolve => {
        ...get auth object...
        delete auth.then;
        resolve(auth);
      });
    }
    

    【讨论】:

      【解决方案5】:

      自 2022 年 1 月起,这些类型已得到修复。错误不再发生。详情请见pull request

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-22
        • 2019-01-01
        • 1970-01-01
        • 2020-10-03
        • 1970-01-01
        • 2015-11-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多