Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flow (InferError): Cannot get 'object[key]' because an index signature declaring the expected key / value type is missing in 'Class'

Here's my code to test equality of some class objects. See my other question if you want to know why I'm not just doing expect(receivedDeals).toEqual(expectedDeals) and other simpler assertions.

   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]);
        }
      });
    });

The test passes fine, but I'm getting a Flow error on expected[key]:

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

I can paste in code from Deal by request, but I think all you need to know is that I haven't declared an index signature (because I don't know how!).

I've searched around a bit but I can't find this exact case.

Update: I can eliminate the errors by changing deal and expected thusly:

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

And since I'm comparing properties in the loop this isn't really a problem. But I would think that I should be able to do this with Deals, and I'd like to know how I declare the index signature mentioned in the error.

PS. Bonus question: In some world where a mad scientist crossbred JS with Swift, I imagine you could do something like

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);

Is this a thing at all?

Edit:

Adding a bit of the definition of Deal class:

Deal.js (summary)

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;
  }
}
like image 922
Jonathan Tuzman Avatar asked Oct 23 '25 04:10

Jonathan Tuzman


1 Answers

An index signature (or indexer property) is defined as [keyName: KeyType]: ValueType. DealCollection is a great example: the keyName is key, the KeyType is number and the ValueType is Deal. This means that whenever you access a number property of an object of type DealCollection, it will return a Deal. You will want to add a similar expression to the definition of Deal in order to access arbitrary properties on it. More information can be found at the Objects as maps section in the Flow documentation.

like image 116
user11307804 Avatar answered Oct 25 '25 17:10

user11307804



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!