简体   繁体   English

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

[英]TypeScript: Promise.all doesn't handle union types

I have the following piece of code that results in compile error in TypeScript:我有以下一段代码导致 TypeScript 编译错误:

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

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

The error is as follows错误如下

No overload matches this call.没有重载匹配这个调用。 The last overload gave the following error.最后一次重载给出了以下错误。 Argument of type '(Promise | Promise)[]' is not assignable to parameter of type 'Iterable>'. '(Promise | Promise)[]' 类型的参数不可分配给 'Iterable>' 类型的参数。 The types returned by 'Symbol.iterator.next(...)' are incompatible between these types. 'Symbol.iterator.next(...)' 返回的类型在这些类型之间不兼容。

For the record, removing the union type works as intended:作为记录,删除联合类型按预期工作:

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

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

You can see the error for yourself here https://www.typescriptlang.org/play/?ssl=4&ssc=3&pln=1&pc=1#code/C4TwDgpgBACgTgewLYEsDOBDARgG2gXigAoiBKKfAPlkVTQgB41g4UA7Ac0vIB9iyK1eMnSM2AVyRYIcbgG4AsACgAxgjbMoAM3FsVFKBjQg9xMLXTY8ALhojMuCOSpQA3sqiGA7hhTA7dBAAdBg4OEQA2ub2VhBkALqkikoAvnJAA你可以在这里看到的错误自己https://www.typescriptlang.org/play/?ssl=4&ssc=3&pln=1&pc=1#code/C4TwDgpgBACgTgewLYEsDOBDARgG2gXigAoiBKKfAPlkVTQgB41g4UA7Ac0vIB9iyK1eMnSM2AVyRYIcbgG4AsACgAxgjbMoAM3FsVFKBjQg9xMLXTY8ALhojMuCOSpQA3sqiGA7hhTA7dBAAdBg4OEQA2ub2VhBkALqkikoAvnJAA

Is it not possible to use union types in combination with Promise.all ?是否不能将联合类型与Promise.all结合使用?

EDIT: I know it's possible to use something like () => Promise<string|number> instead.编辑:我知道可以使用() => Promise<string|number> But in an advanced application with a lot of asynchronous functions and big types, it is not easy to convert union of functions into function of union.但是在一个异步函数很多、类型很大的高级应用中,把函数的联合转换成联合的函数并不容易。 It's not very practical from the code perspective as well.从代码的角度来看,它也不是很实用。

Update更新

This is one of the cases, where type inference with current promise type declarations fails.这是使用当前promise 类型声明进行类型推断失败的情况之一。 Simplest solution is to just add the generic type argument manually:最简单的解决方案是手动添加泛型类型参数:

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

You might infer string | number您可能会推断string | number string | number automatically:自动string | number

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

With TypeScript 4.1 : More complex, potentially nested Promise types can be resolved and flattened with a custom recursive Awaited type like this:使用TypeScript 4.1 :更复杂的、潜在嵌套的 Promise 类型可以使用自定义递归Awaited类型来解析和扁平化,如下所示:

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

Playground 操场



Old answer旧答案

Update: The awaited type operator is delayed to later versions - not clear whether it will be released at all.更新: awaited类型运算符被延迟到更高版本- 根本不清楚它是否会被释放。


This is a known issue .这是一个已知问题 Good news: TS 3.9 (beta soon) will come out with improved promise types :好消息: TS 3.9 (即将推出测试版)将推出改进的承诺类型

I would like to reintroduce the awaited type operator from #17077 to meet our needs for a mechanism to recursively unwrap a Promise-like type for methods like Promise.all , Promise.race , Promise.allSettled , Promise.prototype.then , and Promise.prototype.catch .我想再次引入awaited从操作型#17077 ,以满足我们的机制需要递归地展开一个承诺般的类型等的方法Promise.allPromise.racePromise.allSettledPromise.prototype.then ,并Promise.prototype.catch

Type declarations of Promise.all and others use the new awaited type operator. 类型声明Promise.all和其他人使用的新awaited类型运营商。 If you test with the nightly build , Promise.all now correctly resolves to Promise<(string | number)[]> :如果您使用 nightly build 进行测试Promise.all现在可以正确解析为Promise<(string | number)[]>

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

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

In contrast, TS 3.8 can't handle it .相比之下,TS 3.8 处理不了 For versions < 3.9, you can manually assign the generic type argument:对于版本 < 3.9,您可以手动分配泛型类型参数:

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

You don't need such a verbose type, this will do:你不需要这样一个冗长的类型,这会做:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM