拒绝带有错误的 Promise 时出现 TypeScript 错误 TS2345

TypeScript error TS2345 when rejecting a Promise with an error

我有一条 TypeScript 错误消息,我不明白其中的错误。错误信息是:

error TS2345: Argument of type '(error: Error) => void | Promise' is not assignable to parameter of type '(reason: any) => IdentityKeyPair | PromiseLike'. Type 'void | Promise' is not assignable to type 'IdentityKeyPair | PromiseLike'.

我的代码运行良好,但当我更改此块时 TypeScript 对我很生气:

.catch((error) => {
  let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
  return this.store.save_identity(identity);
})

进入这个:

.catch((error) => {
  if (error instanceof RecordNotFoundError) {
    let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
    return this.store.save_identity(identity);
  } else {
    return reject(error);
  }
})

这是完整的有效代码:

public init(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.store.load_identity()
      .catch((error) => {
        let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
        return this.store.save_identity(identity);
      })
      .then((identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
      })
      .then((lastResortPreKey: Proteus.keys.PreKey) => {
        return resolve(lastResortPreKey);
      })
      .catch(reject);
  });
}

这里是不再编译的代码:

public init(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.store.load_identity()
      .catch((error) => {
        if (error instanceof RecordNotFoundError) {
          let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
          return this.store.save_identity(identity);
        } else {
          return reject(error);
        }
      })
      .then((identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
      })
      .then((lastResortPreKey: Proteus.keys.PreKey) => {
        return resolve(lastResortPreKey);
      })
      .catch(reject);
  });
}

有谁知道为什么 TypeScript 编译器拒绝我的 return reject(error); 错误代码为 TS2345 的语句?

截图:

我正在使用 TypeScript 2.1.4。

你的return在那里没用,它是onRejection回调的结尾。 return reject() 无论如何都会实现下一个 .then() 承诺。 但是,如果您抛出错误,它将在以下承诺中继承到 .catch(reject);

基本上:在任何 catch/then 中,return 将解析子承诺,而抛出将拒绝子承诺。

我重写了您的代码以更好地流动承诺链。

public init(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.store.load_identity()
    .catch(
      (error) => {
        if (error instanceof RecordNotFoundError) {
          let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
          return this.store.save_identity(identity);
        } else {
          throw error;
        }
      }
    )
    .then(
      (identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        resolve(this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID));
      },
      reject
    )
  });
}

试试下面的。当您在 then 或 catch 块中时,您可以 return Promise 或包装到 Promise 中的值。您自己手动使用 Promise,因此您可以调用 resolve 和 reject 处理程序,而无需 return 任何操作。返回 reject(error) 会尝试获取 returned 值,将其包装在 Promise 中,然后尝试传递到下一个 then 块,这就是您收到错误的原因。可以这样想:return在处理程序中添加一些东西意味着使用这个新值继续沿着链向下。在你的情况下,我认为你只是想停止链接并让你正在创建的承诺在某些条件下解决或拒绝。

public init(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.store.load_identity()
      .catch((error) => {
        if (error instanceof RecordNotFoundError) {
          let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
          return this.store.save_identity(identity);
        } else {
          throw error;
        }
      })
      .then((identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
      })
      .then((lastResortPreKey: Proteus.keys.PreKey) => {
        resolve(lastResortPreKey);
      })
      .catch((error) => {
        reject(error);
      });
  });
}

你不能停止 Promise 链(除了取消),甚至 returnning reject() 也不能,这绝对是对 Promise 的误用(你不应该包装 Promise在另一个 Promise 构造函数中)。

让我们从你能做什么开始,然后再去你应该做什么。

您可以让拒绝在 Promise 链中冒泡,当它与您的类型保护不匹配时重新throw处理它,并且在行的底部,毕竟 .catch()子句自身耗尽,从你的函数返回的 Promise 将被拒绝。

现在

想想你将如何在同步代码中做到这一点。你会有这样的东西:

try {
  try {
    actionThatThrows();
  } catch (err) {
    breakEverything();
  }
  continue other steps
} catch(err) {
  generalErrorHandling();
}

那种代码不行,在Promises中也不行。您应该将不同的操作移动到可以自行解决或拒绝的函数中,按原样使用错误,一个在堆栈中冒泡直到遇到可以处理它的异常。

另外,因为您使用的是 TS 2。1.x,对于长异步流,建议使用 异步函数