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?
Adding a bit of the definition of Deal class:
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;
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With