combo: add `shape` helper utility (#1823)

Summary:
Users may now write `C.shape(fields)` instead of `C.object({}, fields)`.

Test Plan:
Unit tests included.

wchargin-branch: combo-shape
This commit is contained in:
William Chargin 2020-05-31 21:48:23 -07:00 committed by GitHub
parent 4635b46d1f
commit 930ac715fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 0 deletions

View File

@ -209,6 +209,12 @@ type PObjectWithOptionals = <FReq: Fields, FOpt: Fields>(
}> }>
>; >;
// Parser combinator for an object type where all fields are optional.
// Special case of `PObjectWithOptionals`.
type PObjectShape = <FOpt: Fields>(
optional: FOpt
) => Parser<$Rest<$Exact<$ObjMap<FOpt, ExtractFieldOutput>>, {}>>;
// Parser combinator for an object type with some required fields (maybe // Parser combinator for an object type with some required fields (maybe
// none) and maybe some optional ones. (This is an intersection type // none) and maybe some optional ones. (This is an intersection type
// rather than a normal function with optional second argument to force // rather than a normal function with optional second argument to force
@ -269,3 +275,9 @@ export const object: PObject = (function object(
return success(result); return success(result);
}); });
}: any); }: any);
// Create a parser for an object type all of whose fields are optional.
// Shorthand for `object` with an empty first argument.
export const shape: PObjectShape = function shape(fields) {
return object({}, fields);
};

View File

@ -371,4 +371,29 @@ describe("src/util/combo", () => {
C.rename("hmm", C.rename("old", C.string)); C.rename("hmm", C.rename("old", C.string));
}); });
}); });
describe("shape", () => {
// Light test; this is a special case of `object`.
it("works for normal and renamed fields", () => {
const p: C.Parser<{|
+one?: number,
+two?: number,
+three?: number,
+four?: number,
|}> = C.shape({
one: C.number,
two: C.rename("dos", C.number),
three: C.number,
four: C.rename("cuatro", C.number),
});
expect(p.parseOrThrow({one: 1, dos: 2})).toEqual({one: 1, two: 2});
});
it("type-errors if the output has any required fields", () => {
// $ExpectFlowError
const _: C.Parser<{|+a?: null, +b: null /* bad */|}> = C.shape({
a: C.null_,
b: C.null_,
});
});
});
}); });