TypeScript:Promise.all不处理联合类型

时间:2020-03-19 13:36:32

标签: typescript promise union-types

我有以下代码导致TypeScript的编译错误:

type Promisable = (() => Promise<string>) | (() => Promise<number>);

const func = async (promisable: Promisable) => {
  await Promise.all([promisable()]);
};

错误如下

没有重载匹配此调用。 最后一次重载给出了以下错误。 类型'(Promise | Promise)[]'的参数不能分配给类型'Iterable>'的参数。 这些类型之间由'Symbol.iterator.next(...)'返回的类型不兼容。

为记录起见,删除联合类型按预期进行:

type Promisable = () => Promise<string>;

const func = async (promisable: Promisable) => {
  await Promise.all([promisable()]);
};

您可以在https://www.typescriptlang.org/play/?ssl=4&ssc=3&pln=1&pc=1#code/C4TwDgpgBACgTgewLYEsDOBDARgG2gXigAoiBKKfAPlkVTQgB41g4UA7Ac0vIB9iyK1eMnSM2AVyRYIcbgG4AsACgAxgjbMoAM3FsVFKBjQg9xMLXTY8ALhojMuCOSpQA3sqiGA7hhTA7dBAAdBg4OEQA2ub2VhBkALqkikoAvnJAA

看到自己的错误

是否可以将联合类型与Promise.all结合使用?

编辑: 我知道可以改用() => Promise<string|number>之类的东西。但是,在具有大量异步函数和大类型的高级应用程序中,将函数的联合转换为联合的函数并不容易。从代码角度来看,它也不是很实用。

2 个答案:

答案 0 :(得分:5)

更新

这是其中一种情况,其中type inference与当前promise type declarations一起失败。 最简单的解决方案是手动添加通用类型参数:

const promisable: Promisable = ...
const res = await Promise.all<string | number>([promisable()]); 
// res: (string|number)[]

您可能会自动推断string | number

type PromiseReturn<T> = T extends () => Promise<infer I> ? I : never
const res = await Promise.all<PromiseReturn<Promisable>>([promisable()]);

使用TypeScript 4.1:更复杂的,可能嵌套的Promise类型可以通过custom recursive Awaited type进行解析和扁平化:

type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;

Playground



旧答案

更新awaited类型的运算符为delayed to later versions-不清楚是否将其完全释放。


这是known issue。好消息:TS 3.9(即将推出测试版)将与improved promise types一同发布:

我想从#17077重新引入awaited类型运算符,以满足我们对Promise.all,{{1}等方法的递归解开Promise类型的机制的需求},Promise.racePromise.allSettledPromise.prototype.then

Promise.prototype.catch中的

Type declarations和其他人使用新的Promise.all类型的运算符。如果您test with the nightly buildawaited现在可以正确解析为Promise.all

Promise<(string | number)[]>

相比之下,TS 3.8 can't handle it。对于3.9以下的版本,您可以manually assign通用类型参数:

type Promisable = (() => Promise<string>) | (() => Promise<number>);

declare const promisable: Promisable
const res = await Promise.all([promisable()]); // res: (string | number)[]

答案 1 :(得分:0)

您不需要这种冗长的类型,这可以做到:

type Promisable = (() => Promise<string|number>);
const func = async (promisable: Promisable) => {
  await Promise.all([promisable()]);
};