我制作了一个类来批量处理promise,并根据给出的键返回结果。例如,如果给它两个名为await Task.Run
和order
的键,每个键都有一个Promise,它将解决这些Promise,并以这些键作为属性,将解析的值作为它们各自的值,返回一个对象。
这是此类的用法:
customer
这是实际的实现:
const batchPromiseHandler = new BatchPromise();
// getCustomerInfo and getPaymentInfo will give back a promise which resolves into their data
batchPromiseHandler.add('order', getOrderInfo());
batchPromiseHandler.add('customer', getCustomerInfo());
// await to resolve all into result object
const result = await batchPromiseHandler.resolveAll();
console.log(result.order); // <<-- I want to be able to get suggestion order or customer from IDE
console.log(result.customer);
它可以正常工作,但是我希望能够从type resultDecorator = (data: any[], index: number) => any;
class BatchPromise {
private promiseList: Promise<any>[] = [];
private keyList: string[] = [];
private decoratorList: resultDecorator[] = [];
add(key: string, promise: Promise<any>, decorator?: resultDecorator): void {
if (this.keyList.indexOf(key) !== -1) {
throw new Error(`Key: "${key}" already exists in PromiseLand!`);
}
this.promiseList.push(promise);
this.keyList.push(key);
this.decoratorList.push(decorator);
}
async resolveAll(): Promise<{ [key: string]: any }> { // <<------ here is naive return type
const resolvedArray = await Promise.all(this.promiseList);
const result = {};
for (let index = 0; index < this.promiseList.length; index++) {
const key = this.keyList[index];
result[key] =
typeof this.decoratorList[index] === 'function'
? await this.decoratorList[index](resolvedArray[index], index)
: resolvedArray[index];
}
return result;
}
}
函数获得结果的自动完成功能。我不知道如何使用语言的动态类型功能,所以我只是这样做了:
resolveAll
如何重构它以使其能够获得IDE向我推荐的Promise<{ [key: string]: any }>
或order
?
答案 0 :(得分:2)
这里的问题是类型BatchPromise
对它所持有的特定键和值一无所知。如果要跟踪它,它必须是generic类型,例如BatchPromise<T>
,其中T
是表示{{ 1}}。
resolveAll()
因此,每次调用class BatchPromise<T extends object = {}> {
...
async resolveAll(): Promise<T> { ... }
}
时,您将从add()
变为BatchPromise<T>
,其中BatchPromise<T & Record<K, V>>
和K
是您的关键和价值类型。这有点麻烦:类型系统不支持任意更改现有对象的类型。如果您小心一点,可以编写V
,以便将BatchPromise
视为缩小的类型,该类型受 支持。这将需要使用assertion function(以便add()
返回add
)。但是断言函数现在还不太容易使用(请参阅microsoft/TypeScript#33622),因此我将不提供这种解决方案。
如果asserts this is BatchPromise<T & Record<K, V>>
返回修改后类型的bp.add()
对象,则不会使bp
方法更改bp.add()
的类型,而是在类型系统中变得更好了。 :
BatchPromise
为了使其正常工作,您需要更改调用 add<K extends string, V>(
key: K, promise: Promise<V>, decorator?: resultDecorator
): BatchPromise<T & Record<K, V>> {
...
return this as BatchPromise<T & Record<K, V>>;
}
的方式以合并method chaining而不是多个语句:
add()
这样,您的const batchPromiseHandler = new BatchPromise()
.add('order', getOrderInfo())
.add('customer', getCustomerInfo());
的类型将为batchPromiseHandler
。
让我们看看是否可行
BatchPromise<{order: OrderInfo, customer: CustomerInfo}>
看起来不错。而且,您可以(通过下面的Playground链接)验证IDE的IntelliSense能够提示const result = await batchPromiseHandler.resolveAll();
result.customer; // CustomerInfo
result.order; // OrderInfo
result.randomThing; // error!
// Property 'randomThing' does not exist on type
// 'Record<"order", OrderInfo> & Record<"customer", CustomerInfo>'
具有result
和customer
属性。
好的,希望能给您前进的道路。祝好运!