打字并承诺确定结果

问题描述 投票:0回答:1

我正在尝试编写一个函数,该函数接受

PromiseSettledResult
数组(Promise.allSettled 返回的 类型)并返回已完成值或拒绝原因的数组:

function unwrapResults<T>(results: ReadonlyArray<PromiseSettledResult<T>>): Array<T> {
    return results.map((result) => result.status === "fulfilled" ? result.value : result.reason);
}

它在以下示例中工作:

const results = await Promise.allSettled([
    Promise.resolve(1),
    Promise.resolve("ok"),
    Promise.reject(new Error("error"))
]);

const unwrappedResults = unwrapResults<number | string | Error>(results);

问题在于:

  • 我需要明确地将所有可能的已解决结果类型的并集作为
    unwrapResults
    类型。
  • unwrappedResults
    内的元素将是
    number | string | Error
    类型。

有没有办法改善这个问题?理想情况下,我希望函数调用中的手动输入更少,并且

unwrappedResults[0]
成为
number
unwrappedResults[1]
成为
string
unwrappedResults[2]
成为
Error

typescript
1个回答
0
投票

我要说的是,它不能按您期望的方式工作的原因是由于打字稿中关于如何检查泛型和联合类型的限制。具体来说,因为

PromiseSettledResult<string | number>
PromiseSettledResult<string> | PromiseSettledResult<number>
不同,联合体最终的结构略有不同,因为它们由打字稿表示,但
.value
字段最终都将是
string | number

因此,要使其正常工作,我们必须将泛型提升一个级别并表示

PromiseSettledResult
类型,然后使用条件类型从泛型中提取
.value
字段。 类似这样的事情

type UnwrappedSettled<T extends PromiseSettledResult<any>> = T extends PromiseFulfilledResult<infer V> ? V : Error 
function unwrapOneResult<T extends PromiseSettledResult<unknown>>(result: T): UnwrappedSettled<T>{
    return result.status === "fulfilled" ? result.value : result.reason
}
async function test(){
    const results = await Promise.allSettled([
        Promise.resolve(1),
        Promise.resolve("ok"),
        Promise.reject(new Error("error"))
    ]);
    const unwrapped = results.map(unwrapOneResult)
    // ^? const unwrapped: (string | number | Error)[]
}

那么写你的

unwrapResults
同样容易

function unwrapResults<T extends PromiseSettledResult<any>>(results: T[]): Array<UnwrappedSettled<T>> {
    return results.map(unwrapOneResult)
}

unwrapOneResult
可以在此版本中内联,它只是用于表明类型安全仍然按照您的预期工作,在内联版本中您会得到
any
而不是
Error
,所以它不会'严格进行类型检查。

© www.soinside.com 2019 - 2024. All rights reserved.