我想为 Promise.allSettled 创建一些通用处理
目前 allSettled 返回已完成和已拒绝结果的列表。我不在乎,我真的不想到处处理它。 我想像 Promise.all 一样使用它 如果有任何错误,则拒绝,但要等到一切结束。这很重要。
private async allAndWait<T>(values: Iterable<PromiseLike<T>>): Promise<T[]> {
const allSettled = await Promise.allSettled(values);
const rejected = allSettled.find((promise) => promise.status === 'rejected') as PromiseRejectedResult | undefined;
if (rejected) {
throw rejected.reason;
}
return allSettled.map((promise) => (promise as PromiseFulfilledResult<T>).value);
}
创建了类似的东西,但它不允许我发送不同类型的承诺数组。而且返回类型只是第一种类型,而我想拥有和Promise.all一模一样的体验
总长:
async function allAndWait<T extends readonly unknown[] | []>(values: T & Iterable<PromiseLike<unknown>>): Promise<{-readonly [key in keyof T]: Awaited<T[key]>}>
async function allAndWait<T extends PromiseLike<unknown>>(values: Iterable<T>): Promise<Awaited<T>[]>
async function allAndWait<T extends readonly unknown[] | []>(values: Iterable<PromiseLike<unknown>>): Promise<any> {
const allSettled = await Promise.allSettled(values) as PromiseSettledResult<Awaited<T[number]>>[]
const rejected = allSettled.find((promise) => promise.status === 'rejected') as PromiseRejectedResult | undefined;
if (rejected) {
throw rejected.reason;
}
return allSettled.map((promise) => (promise as PromiseFulfilledResult<Awaited<T[number]>>).value)
}
这是我希望可以理解的过程:
我不知道为什么,但在你的代码中
T
没有被正确推断。我预计 T
是输入元组所具有的所有类型的联合(因此 string | number
)。我们可以通过将类型减速转移到通用减速来做到这一点。 (只需移动 PromiseLike<unknown>
就足够了)。
async function allAndWait<T extends Iterable<PromiseLike<unknown>>>(values: T) ...
这确实对我们没有多大帮助,因为我们需要 T 是一个元组而不是一个并集。正如您希望对返回类型进行排序(并非所有返回类型都是所有输入类型的并集类型)。我们是否以
[PromiseLike<string>, PromiseLike<number>]
或 [string, number]
的形式获得这样的元组并不重要,因为我们可以使用映射类型从前者中提取类型。所以假设我们有这样一个(PromiseLike)元组T
我们可以简单地做:
{[key in keyof T]: Awaited<T[key]>}
我的第一直觉是使用休息运算符:
async function allAndWait<T extends Promise<unknown>[]>(...values: T): Promise<{[key in keyof T]: Awaited<T[key]>}> {...}
allAndWait(Promise.resolve("qwe"), Promise.resolve(2)) // typeof Promise<[string, number]>
请注意,我们必须将
Iteratable
放在数组上。因为我们不能在 Iteratable
上使用剩余运算符。请注意,Iteratable
与元组类型不同。所以我们不能说第一个元素是字符串类型,第二个元素是数字类型,这是我们这里需要的。我们稍后可以对此用例进行重载(如果您确实需要它),并提供一个与联合一起使用的不太强大的类型实现。但首先我们需要解决你甚至不能传入数组的问题。你可以这样做:
const arr = [Promise.resolve("string"), Promise.resolve(2)]
allAndWait(...arr)
但这并不严格遵循您请求的类型实现。请注意,我们不能只从函数减速中省略剩余运算符,因为这会再次将元组转换为联合类型。所以我们必须应用一个技巧:
async function allAndWait<T extends readonly unknown[] | []>(values: T & Iterable<Promise<unknown>>): Promise<{-readonly [key in keyof T]: Awaited<T[key]>}> {...}
我们通过交集类型在这里需要两件事:首先,
values
必须是IterableT
,以便我们稍后可以将其用于导出。这行代码很大程度上受到 Promise.all
类型声明的启发,我不知道为什么在这里: T extends readonly unknown[] | []
与 []
的联合是必要的,但确实如此。
这只会为
Iteratable
s 留下不太强大的过载:
async function allAndWait<T extends PromiseLike<unknown>>(values: Iterable<T>): Promise<Awaited<T>[]>
我们必须将其放在另一个重载下方,因为它更通用并且符合所有可能的输入(因此永远不会达到另一个重载)。