MapUtil: provide exact output from `toObject` (#993)
Summary: The `MapUtil` map–object conversion functions used inexact objects for both input and output. They are in fact stronger than that: they can accept arbitrary inexact objects and return arbitrary exact outputs. (Recall that exact objects are subtypes of their inexact counterparts, so this is the maximally permissive combination.) Test Plan: Unit tests added. The “can return an exact object” test fails Flow before this change. The other tests would have passed already. wchargin-branch: maputil-exact-output
This commit is contained in:
parent
252d8d5c99
commit
beccac822f
|
@ -7,8 +7,8 @@
|
||||||
*/
|
*/
|
||||||
export function toObject<K: string, V, InK: K, InV: V>(
|
export function toObject<K: string, V, InK: K, InV: V>(
|
||||||
map: Map<InK, InV>
|
map: Map<InK, InV>
|
||||||
): {[K]: V} {
|
): {|[K]: V|} {
|
||||||
const result = {};
|
const result: {|[K]: V|} = ({}: any);
|
||||||
for (const [k, v] of map.entries()) {
|
for (const [k, v] of map.entries()) {
|
||||||
result[k] = v;
|
result[k] = v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,14 @@ describe("util/map", () => {
|
||||||
const output: {[Fruit]: string} = MapUtil.toObject(input);
|
const output: {[Fruit]: string} = MapUtil.toObject(input);
|
||||||
expect(output).toEqual({APPLE: "good", ORANGE: "also good"});
|
expect(output).toEqual({APPLE: "good", ORANGE: "also good"});
|
||||||
});
|
});
|
||||||
|
it("can return an exact object", () => {
|
||||||
|
const _: {|[string]: number|} = MapUtil.toObject(new Map().set("a", 1));
|
||||||
|
});
|
||||||
|
it("can return an inexact object", () => {
|
||||||
|
// This should be free: exact objects are subtypes of their
|
||||||
|
// inexact counterparts.
|
||||||
|
const _: {[string]: number} = MapUtil.toObject(new Map().set("a", 1));
|
||||||
|
});
|
||||||
it("statically rejects a map with keys not a subtype of string", () => {
|
it("statically rejects a map with keys not a subtype of string", () => {
|
||||||
const input: Map<number, string> = new Map()
|
const input: Map<number, string> = new Map()
|
||||||
.set(12, "not okay")
|
.set(12, "not okay")
|
||||||
|
@ -53,6 +61,16 @@ describe("util/map", () => {
|
||||||
new Map().set("APPLE", "good").set("ORANGE", "also good")
|
new Map().set("APPLE", "good").set("ORANGE", "also good")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it("can accept an inexact object", () => {
|
||||||
|
const o: {[string]: number} = {a: 1};
|
||||||
|
const _: Map<string, number> = MapUtil.fromObject(o);
|
||||||
|
});
|
||||||
|
it("can accept an exact object", () => {
|
||||||
|
// This should be free: exact objects are subtypes of their
|
||||||
|
// inexact counterparts.
|
||||||
|
const o: {|[string]: number|} = ({a: 1}: any);
|
||||||
|
const _: Map<string, number> = MapUtil.fromObject(o);
|
||||||
|
});
|
||||||
it("statically rejects a map with keys not a subtype of string", () => {
|
it("statically rejects a map with keys not a subtype of string", () => {
|
||||||
const input: {[number]: string} = {};
|
const input: {[number]: string} = {};
|
||||||
input[12] = "not okay";
|
input[12] = "not okay";
|
||||||
|
|
Loading…
Reference in New Issue