【问题标题】:Bluebird / Typescript Error: 'this' context of is not assignable to method's 'this'Bluebird / Typescript 错误:“this”的上下文不可分配给方法的“this”
【发布时间】:2021-09-26 15:25:09
【问题描述】:

我有一系列方法(有些是异步的,有些不是),我想使用bluebird.each 来按顺序处理。这是一个简单的例子:

import bluebird from 'bluebird';

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
class Template {
  propertyA!: number;
  propertyB!: number;
  constructor() {}
  async methodA() {
    this.propertyA = 10;
    console.log({ thisArgInA: this, propertyA: this.propertyA });
    await delay(500);
    return this.propertyA;
  }
  methodB() {
    this.propertyB = this.propertyA * 100;
    console.log({ thisArgInB: this, propertyB: this.propertyB });
    return this.propertyB;
  }
}

const instance = new Template();

const sequence = [instance.methodA, instance.methodB];

(async function main() {
  await bluebird.each(sequence, (fn) => {
    const result = fn.call(instance);
    console.log({ result });
  });
})();

这会产生这个我不明白的错误:

index.ts:27:20 - error TS2684: The 'this' context of type '(() => Promise<number>) | (() => number)' is not assignable to method's 'this' of type '(this: Template) => Promise<number>'.
  Type '() => number' is not assignable to type '(this: Template) => Promise<number>'.
    Type 'number' is not assignable to type 'Promise<number>'.

27     const result = fn.call(instance);

我想可能是因为bluebird.each 接受解析为编译器无法协调的值的值或承诺,但我想到的唯一解决方案是强类型返回值”

async methodA: Promise<number> { /*...*/ }
methodB: number { /*...*/ }

但这并没有改变任何东西。我还注意到以下几点:

  • 我必须在这里提供上下文,因为调用each 回调中的函数会失去与Template 的连接,因为this
  • methodA同步时(去掉async关键字,去掉delay(),直接返回this.propertyA,就可以了。
  • 当我删除 return 语句时,一切正常。
  • 当我将 fn.call(instance) 更改为 fn.bind(instance)() 时,它工作正常

我怎样才能满足编译器的要求,让它知道如何使用提供的上下文调用这些函数。

有没有更简单的方法可以按顺序调用这些方法,从而保持它们与this 的连接?

StackBlitz Example

【问题讨论】:

  • 问题:你为什么要使用蓝鸟?当 Promises 还不是真实的东西时,它是有道理的,但 the Promise API 多年来一直是规范的一部分。只需使用它,然后从您的代码库中删除旧依赖项?特别是考虑到 async 使函数返回标准 Promise,而无需显式编写 Promise 代码。然后您可以使用await 处理它就像 您正在编写同步代码,而不需要promise then().catch() 语法。
  • 我无法在您提供的 StackBlitz 上重现该问题。运行tsc 不会输出任何错误。
  • @Mike'Pomax'Kamermans 所以只删除 bluebird 并在 for-of 循​​环中处理 sequence 中的函数会是更好的解决方案吗?
  • @Bergi 我认为你必须运行npx ts-node index.ts。我不确定您是否可以在该环境中进行像 tsc 这样的全局安装。
  • 在 typescript 操场上没有蓝鸟的情况下可以重现错误

标签: javascript typescript async-await this bluebird


【解决方案1】:

查看推断的类型可能会有所帮助:

  • sequence: (((this: Template) =&gt; number) | ((this: Template) =&gt; Promise&lt;number&gt;))[] 或只是 ((() =&gt; Promise&lt;number&gt;) | (() =&gt; number))[]
  • fn: ((this: Template) =&gt; number) | ((this: Template) =&gt; Promise&lt;number&gt;) 或只是 (() =&gt; Promise&lt;number&gt;) | (() =&gt; number)
  • .call: &lt;Template, [], number&gt;(this: (this: Template) =&gt; number, thisArg: Template): number

我们可以看到.call() 表达式的类型不是我们所期望的——编译器想要一个返回number 的函数,并抱怨fn 可以返回Promise&lt;number&gt;。这可能是由于在处理推断函数联合类型的返回类型时出现的 TypeScript 错误。可能与subtle difference between X =&gt; A | B and (X =&gt; A) | (X =&gt; B)有关。

我们可以通过编写来解决这个问题

  • const result = fn.call&lt;Template,[],number|Promise&lt;number&gt;&gt;(instance);
  • …(fn: () =&gt; number | Promise&lt;number&gt;)) =&gt; …
  • const sequence: (() =&gt; number | Promise&lt;number&gt;)[]

【讨论】:

  • call 的后两个类型参数是什么?当我尝试时,我得到Expected 0 type arguments, but got 3.
  • @1252748 它们似乎是要调用的函数的参数和返回类型。 It works for me.
猜你喜欢
  • 2022-06-12
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
  • 2019-08-26
  • 1970-01-01
  • 2019-06-10
  • 2021-04-18
  • 2018-01-23
相关资源
最近更新 更多