【问题标题】:Flow (InferError): Cannot get 'object[key]' because an index signature declaring the expected key / value type is missing in 'Class'流(推断错误):无法获取“对象 [键]”,因为“类”中缺少声明预期键/值类型的索引签名
【发布时间】:2019-11-13 07:42:47
【问题描述】:

这是我测试某些类对象是否相等的代码。如果你想知道我为什么不只是在做,请看我的other question expect(receivedDeals).toEqual(expectedDeals) 和其他更简单的断言。

   type DealCollection = { [key: number]: Deal };  // imported from another file

   it("does the whole saga thing", async () => {
      sagaStore.dispatch(startAction);
      await sagaStore.waitFor(successAction.type);
      const calledActionTypes: string[] = sagaStore
        .getCalledActions()
        .map(a => a.type);
      expect(calledActionTypes).toEqual([startAction.type, successAction.type]);
      const receivedDeals: DealCollection = sagaStore.getLatestCalledAction()
        .deals;
      Object.keys(receivedDeals).forEach((k: string) => {
        const id = Number(k);
        const deal = receivedDeals[id];
        const expected: Deal = expectedDeals[id];
        for (let key in expected) {
          if (typeof expected[key] === "function") continue;
          expect(expected[key]).toEqual(deal[key]);
        }
      });
    });

测试顺利通过,但我在 expected[key] 上收到 Flow 错误:

Cannot get 'expected[key]' because an index signature declaring the expected key / value type is missing in 'Deal'

我可以通过请求从Deal 粘贴代码,但我想你只需要知道我还没有声明索引签名(因为我不知道如何声明!)。

我搜索了一下,但找不到这个确切的案例。

更新:我可以通过更改 dealexpected 来消除错误:

const deal: Object = { ...receivedDeals[id] };
const expected: Object = { ...expectedDeals[id] };

因为我在循环中比较属性,所以这不是问题。但我想我应该可以用Deals 来做到这一点,我想知道我如何声明错误中提到的索引签名。

附言。额外的问题:在某个疯狂的科学家将 JS 与 Swift 杂交的世界里,我想你可以做类似的事情

const deal: Object = { ...receivedDeals[id] where (typeof receivedDeals[id] !== "function" };
const expected = // same thing
expect(deal).toEqual(expected);

// And then after some recombining of objects:
expect(receivedDeals).toEqual(expectedDeals);

这是一回事吗?

编辑:

添加一点Deal类的定义:

Deal.js(摘要)

export default class Deal {
  obj: { [key: mixed]: mixed };
  id: number;
  name: string;
  slug: string;
  permalink: string;
  headline: string;
  // ...other property definitions

  constructor(obj?: Object) {
    if (!obj) return;
    this.id = obj.id;
    this.name = obj.name;
    this.headline = obj.headline;
    // ...etc
  }

  static fromApi(obj: Object): Deal {
    const deal = new Deal();
    deal.id = obj.id;
    deal.name = obj.name;
    deal.slug = obj.slug;
    deal.permalink = obj.permalink;
    // ...etc
    return deal;
  }

  descriptionWithTextSize(size: number): string {
    return this.descriptionWithStyle(`font-size:${size}`);
  }

  descriptionWithStyle(style: string): string {
    return `<div style="${style}">${this.description}</div>`;
  }

  distanceFromLocation = (
    location: Location,
    unit: unitOfDistance = "mi"
  ): number => {
    return distanceBetween(this.location, location);
  };

  distanceFrom = (otherDeal: Deal, unit: unitOfDistance = "mi"): number => {
    return distanceBetween(this.location, otherDeal.location);
  };

  static toApi(deal: Deal): Object {
    return { ...deal };
  }

  static collectionFromArray(array: Object[]) {
    const deals: DealCollection = {};
    array.forEach(p => (deals[p.id] = Deal.fromApi(p)));
    return deals;
  }
}

【问题讨论】:

    标签: javascript flowtype


    【解决方案1】:

    索引签名(或索引器属性)定义为[keyName: KeyType]: ValueTypeDealCollection 就是一个很好的例子:keyNamekeyKeyTypenumberValueTypeDeal。这意味着每当您访问DealCollection 类型对象的数字属性时,它将返回Deal。您需要在Deal 的定义中添加一个类似的表达式,以便访问其上的任意属性。更多信息可以在 Flow 文档的Objects as maps 部分找到。

    【讨论】:

    • 谢谢,我想我明白你在说什么。但是要添加的表达式的语法是什么?我尝试在属性定义中添加{ [key: mixed]: mixed };(请参阅上面添加的Deal 的代码;在添加任何签名尝试之前),但这是一个很大的语法错误。我将其更改为 `obj: { [key: mixed]: mixed };` 但这对 Flow 错误没有影响。
    • 哦,我现在看到了这个问题。 Flow 将Object.keys 的返回类型输入为string[],因此Flow 将无法推断deal[key] 已定义。我不知道是否有一个好的 Flow 解决方案。但是,我建议使用 toMatchObject 和/或 expect.any(Function) 而不是循环遍历所有键。
    猜你喜欢
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 2019-04-28
    • 1970-01-01
    • 2019-07-05
    • 1970-01-01
    相关资源
    最近更新 更多