1

バッチで promise を処理し、それらが与えられたキーに基づいて結果を返すクラスを作成しましたordercustomerそれらのキーをプロパティとして、解決された値をそれぞれの値として。

したがって、このクラスの使用方法は次のとおりです。

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ます。言語の動的型機能の使い方がわからないので、次のようにしました。

Promise<{ [key: string]: any }>

たとえば、IDEから取得しorderたり提案したりできるようにリファクタリングするにはどうすればよいですか?customer

4

1 に答える 1

2

ここでの問題は、型BatchPromiseが保持している特定のキーと値について何も知らないことです。これを追跡したい場合は、 のようなジェネリック型である必要がありますBatchPromise<T>。ここで、Tは で返されるキーから値へのマッピングを表すオブジェクト型resolveAll()です。

class BatchPromise<T extends object = {}> { 
  ... 
  async resolveAll(): Promise<T> { ... }
}

したがって、 を呼び出すたびに、 aから a whereにadd()変更され、はそれぞれキーと値の型になります。これにはちょっとした障害があります。型システムは、既存のオブジェクトの型を任意に変更することをサポートしていません。注意すれば、サポートされているタイプを絞り込んでいると見なされるように書くことができます。これは、アサーション関数を使用する必要があります(そのため、 が返されます)。しかし、現時点ではアサーション関数を使用するのは簡単ではないため ( microsoft/TypeScript#33622を参照)、そのようなソリューションを提供するつもりはありません。BatchPromise<T>BatchPromise<T & Record<K, V>>KVBatchPromiseadd()addasserts 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>>;
  }

それが機能するためには、呼び出し方法を変更して、複数のステートメントではなくメソッドチェーンadd()を組み込む必要があります。

const batchPromiseHandler = new BatchPromise()
  .add('order', getOrderInfo())
  .add('customer', getCustomerInfo());

そうbatchPromiseHandlerすれば、あなたは のようなタイプになりますBatchPromise<{order: OrderInfo, customer: CustomerInfo}>


それが機能するかどうか見てみましょう:

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>'

いいね。また、IDE の IntelliSense がおよびプロパティをresult持つプロンプトを表示できることを (以下の Playground リンクを介して) 確認できます。customerorder


さて、それがあなたに前進することを願っています。幸運を!

コードへの遊び場リンク

于 2020-06-13T20:59:32.340 に答える