代码之家  ›  专栏  ›  技术社区  ›  Developerium Acorn

Typescript:具有来自数组值的键的动态对象

  •  0
  • Developerium Acorn  · 技术社区  · 6 年前

    我创建了一个类来批量处理承诺,并根据它们在中给出的键返回结果。例如,如果给它两个名为 order 和 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

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

    例如,我如何重构它以获得 顺序 或 IDE向我提出的建议?

    0 回复  |  直到 6 年前
        1
  •  2
  •   jcalz    6 年前

    这里的问题是 BatchPromise generic 类 BatchPromise<T> 哪里 T 表示中返回的键到值映射的对象类型 resolveAll()

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

    所以每次你打电话 add() ,您将从 承诺<T> BatchPromise<T & Record<K, V>> 哪里 K 和 V 批量承诺 因此 添加() 缩小 类型,其中 是 assertion function (以便 add 返回 asserts this is BatchPromise<T & Record<K, V>> ).但是断言函数现在不是很容易使用(请参见 microsoft/TypeScript#33622

    而不是制造 bp.add() bp ,如果 bp.add() 批量承诺 修改类型的对象:

      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 而不是多个语句:

    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 customer 和 order


    好吧,希望这能给你一个前进的方向。祝你好运

    Playground link to code

    推荐文章