当我从等待移动到 Promise.all 时,TypeScript 函数返回类型错误

Posted

技术标签:

【中文标题】当我从等待移动到 Promise.all 时,TypeScript 函数返回类型错误【英文标题】:TypeScript function return type error when I move from await to Promise.all 【发布时间】:2021-07-17 01:42:53 【问题描述】:

我有一个功能。返回类型是用户的承诺:

async function doThing(): Promise<User> 
  const one = await getOne();
  const two = await getTwo();
  return 
    one,
    two
  

我正在更改函数以使用 Promise.all:

async function doThing(): Promise<User> 
  const onePromise = getOne();
  const twoPromise = getTwo();

  await Promise.all([onePromise, twoPromise])
    .then(([one, two])=>
      return 
        one,
        two
      
    );

但是现在我收到一个 TypeScript 错误:

TS2355:声明类型既不是“void”也不是“any”的函数必须返回一个值。

我很惊讶我在第二版但不是第一版的代码中遇到错误。我尝试捕捉错误,但没有任何区别:

  await Promise.all([onePromise, twoPromise])
    .then(([one, two])=>
      return 
        one,
        two
      
    ).catch(error => 
       return Error(error);
    );

但是在Promise.all 之后抛出错误确实会使错误消失:

  await Promise.all([onePromise, twoPromise])
    .then(([one, two])=>
      return 
        one,
        two
      
    );
    throw new Error("oh no!")

【问题讨论】:

你不需要return承诺吗? return Promise.all...? 也许这只是一个错字或什么?我们应该这样关闭它吗? 【参考方案1】:

正如@jcalz 提到的,您的代码中缺少 return 语句。简短的回答是,.then 中的 return 语句仅返回您在 .then 中定义的函数,而不是更大的 doThing 函数。

在这种情况下,awaitPromise.allPromise.then 都在发挥作用,这有点令人困惑,所以我们可以深入分解它。它可以帮助我隔离方法链中的每个项目并查看它们实际返回的内容。

但首先,让我们回顾一下这些东西的作用:

Promise.all 将承诺列表 (Promise&lt;any&gt;[]) 与列表的承诺 (Promise&lt;any[]&gt;) 组合在一起。这很方便,允许我们只等待一个承诺来获取我们所有的值。

Promise.then 允许我们在 Promise 完成后对其进行操作(类似于 await),在这种情况下可以将该 Promise 转换为不同的类型。这是通过定义一个接受输入值并返回新类型值的函数来完成的。请务必注意,该函数内部的 return 语句决定了 .then 的返回值,而不是调用它的函数。

await:Await 从 Promise 中解包一个值。它还在等待时阻止函数的执行。

所以让我们打破这个链条并添加明确的类型来完成它:

async function doThing(): Promise<User> 

  // Promises are created for whatever type getOne and getTwo return, let's say it's any
  const onePromise: Promise<any> = getOne();
  const twoPromise: Promise<any> = getTwo();

  // Promise.all converts a list of Promises (Promise<any>[]) in to a promise of a list (Promise<any[]>)
  const allPromises: Promise<any[]> = Promise.all([onePromise, twoPromise]);

  // .then convers the Promise of a list (Promise<any[]>) in to a promise of a user (Promise<User>)
  // The function inside takes in the unwrapped any[] and returns whatever we want wrapped in a new promise (User, in this case)
  // Note that the return here is determining the return value for `.then`, NOT for `doThing` because it is nested inside a separate function.
  // `return` statements are subject to scoping rules similar to variable scope
  const userPromise: Promise<User> = allPromises.then((values: any[]) => return  values[0], values[1] );

  // await unwraps the promised user (Promise<User>) to just a User
  const user: User = await userPromise;

  // We can now return, this is the line that was missing from your original code.
  return user;

所以await Promise.all(...).then(...) 链会产生User 对象...但如果没有return 或分配给变量,您的函数不会对其执行任何操作。您的代码只需将 return 添加到该链的前面即可。

在我看来,这可以更简单地完成,无需调用.then,而是等待Promise.all

async function doThing(): Promise<User> 
  const onePromise: Promise<any> = getOne();
  const twoPromise: Promise<any> = getTwo();

  // Promise.all returns Promise<any[]> and awaiting returns any[]
  const values: any[] = await Promise.all([onePromise, twoPromise]);

  // Now we can return directly from here
  return  values[0], values[1] ;

另外,为什么抛出一个新错误会阻止 TypeScript 错误? TypeScript 错误是由 TypeScript 编译器在检测到将执行到最后而不返回值的方法时生成的。通过在函数中抛出错误,您确保解释器将永远到达函数的末尾而没有返回的东西......因为它永远不会到达函数的末尾。所以代码是“正确的”,即使它不起作用。

【讨论】:

以上是关于当我从等待移动到 Promise.all 时,TypeScript 函数返回类型错误的主要内容,如果未能解决你的问题,请参考以下文章

Promise.all() 不等待异步进程

Promise.all() 与等待

结合像Promise.all这样的等待

等待 VS Promise.all

等待Promise.All都没有在Anuglar中等待

Promise.all()函数中的JS“等待仅在异步函数中有效”[重复]