当我从等待移动到 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
函数。
在这种情况下,await
、Promise.all
和 Promise.then
都在发挥作用,这有点令人困惑,所以我们可以深入分解它。它可以帮助我隔离方法链中的每个项目并查看它们实际返回的内容。
但首先,让我们回顾一下这些东西的作用:
Promise.all 将承诺列表 (Promise<any>[]
) 与列表的承诺 (Promise<any[]>
) 组合在一起。这很方便,允许我们只等待一个承诺来获取我们所有的值。
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 函数返回类型错误的主要内容,如果未能解决你的问题,请参考以下文章