如何使用Typescript的Promise.All

时间:2015-11-13 01:44:58

标签: typescript

这是我想要做的:

Promise.all([aurelia.start(), entityManagerProvider.initialize()])
    .then((results:Array<any>) => {
        let aurelia: any = results[0];
        aurelia.setRoot();
    });

aurelia.start()返回Aurelia类型,而initialize()返回void。

编译器会显示一条错误消息,指出无法根据用法推断出该类型。

我想要实现的是让它们同时运行,因为它们都是非常长的进程,然后运行Aurelia.setRoot();

8 个答案:

答案 0 :(得分:42)

这是TypeScript及其Promise.all签名的弱点。通常最好使阵列具有一致的类型。您可以手动执行以下操作:

let foo : [Promise<Aurelia>,Promise<void>] = [aurelia.start(), entityManagerProvider.initialize()];
Promise.all(foo).then((results:any[]) => {
    let aurelia: any = results[0];
    aurelia.setRoot();
});

答案 1 :(得分:22)

由于Promise::all是一个泛型函数,你可以像这样声明每个promise的返回类型:

Promise.all<Aurelia, void>([
  aurelia.start(),
  entityManagerProvider.initialize()
])
.then(([aurelia]) => aurelia.setRoot());

答案 2 :(得分:6)

如果您希望保持类型安全,可以扩展tcp-dump对象的原生类型定义(类型{{1}带有额外的重载签名,用于在使用有限数量的不一定可分配值调用Promise时:

PromiseConstructor

根据需要添加尽可能多的重载。此方法为Promise.all回调的interface PromiseConstructor { all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>; all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>; ... } 参数中的所有元素提供完全类型安全性:

value

答案 3 :(得分:5)

至少从TypeScript 2.7.1开始,编译器似乎在没有帮助的情况下解析类型,语法如下:

Promise.all([fooPromise, barPromise]).then(([foo, bar]) => {
  // compiler correctly warns if someField not found from foo's type
  console.log(foo.someField);
});

帽子小贴士:@JamieBirch(评论@ AndrewKirkegaard的答案)

答案 4 :(得分:3)

第 1 部分

您需要了解一些函数 A) Promise.all 和 B) Promise.then

A) Promise.all 的类型定义是一个函数:

    all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>;

B) Promise.then 的类型定义是一个稍微复杂一点的函数:

    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

第 1 部分.a

Promise.then 的类型定义很多,但可以分解成小部分:

then<TResult1 = T, TResult2 = never> 具有 2 个泛型 then 的函数 TResult1, TResult2< > 表示我们可以稍后在其中设置和使用值 - 它们称为 generics

then 函数本身:(onfulfilled?: ..., onrejected?: ...): Promise<TResult1 | TResult2>

PromiseLike 是辅助类型,与 Promise 相同(用于介绍课程)。

onfulfiledonrejected 是以下形式的函数:(value: T) => (TResult1 OR PromiseLike<TResult1>) OR undefined OR null。请注意此处使用了泛型 T

第 2 部分 -

Promise 本身有一个通用接口:interface Promise<T><T> 是一个/generic

所以当你打电话

Promise.all<SomeCoolType>([a(), b(), c()]).then( value => doSomething(value) )

你的泛型是 SomeCoolType,在这个例子中一些很酷的类型是

interface SomeCoolType = [A() => string, B() => boolean, C() => number]

现在记住 A B C 必须是 Promises。这使得 value 中的 .then( value => ... 将转到 SomeCoolType 的结果,对我们来说,它正在调用所有这些函数,结果是 [string, boolean, number]

结论 -

具体而言,您传递给您的函数/承诺数组 Promise.all<T> 是在 .then(result => ...) 中使用的泛型。这些承诺的返回/解析值将成为 result 的值/类型。

示例:Promise.all<[Promise<() => string>]>([returnStringAsync()]).then(result => console.log(typeof result === "string")); # => true

答案 5 :(得分:0)

我在寻找Promise.all()的返回类型时以某种方式落在这里,因为简单的[Promise<any>, Promise<any>]显然不起作用。

最终,结果似乎比看起来简单:

const severalMongoDbOperations: Promise<[DeleteWriteOpResultObject, UpdateWriteOpResult]> =
  () => Promise.all([
    mongo.deleteOne({ ... }),
    mongo.updateOne({ ... })
  ]);

以后可以与.then()或:

一起使用
try {
  const ops: [DeleteWriteOpResultObject, UpdateWriteOpResult] = await severalMongoDbOperations();
} catch (e) {
  // Process rejection
}

答案 6 :(得分:0)

我对您有同样的问题,但是使用此代码,一切都可以正常工作。

type TList = Promise<Aurelia> | Promise<void>;

const foo: TList[] = [aurelia.start(), entityManagerProvider.initialize()];

Promise.all<TList>(foo).then((results) => {
    let aurelia = results[0];
    aurelia.setRoot();
});

答案 7 :(得分:0)

在使用返回值的 Promise 时,我最喜欢使用 Promise.all() 使用数组重组,如下所示。使用 await 更具可读性,解构是填充正确的变量。

export interface IDeveVersionHubDataService {
    getBuildFilterDeveVersions(): Promise<IBuildFilterDeveVersionDto[]>;
    getBuildFilterUsers(): Promise<IBuildFilterUserDto[]>;
}
const loadDeveVersions = deveVersionHubDataService.getBuildFilterDeveVersions();
const loadUsers = deveVersionHubDataService.getBuildFilterUsers();

const [deveVersions, users] = await Promise.all([loadDeveVersions, loadUsers]);