Expose `NodeTypes` from the GitHub plugin (#96)

Summary:
This is useful for metaprogramming. For instance, suppose we have an
object like this:
```js
const stringifiers = {
  ISSUE: (stringifyIssue: (Node<IssueNodePayload>) => string),
  COMMENT: (stringifyComment: (Node<CommentPayload>) => string),
  ...
}
```
How do we type this? We might try
```js
{[type: NodeType]: (Node<NodePayload>) => string}
```
but this is not correct, because `Node<IssueNodePayload>` is a subtype of
`Node<NodePayload>`, and `(_) => K` is contravariant, not covariant. (In
other words, a function from `Node<IssueNodePayload>` is not as general
as a function from `Node<NodePayload>`.) We need to express a dependency
between the object key and the value. We instead write:
```js
type TypedNodeToStringifier = <T: $Values<NodeTypes>>(
  T
) => (node: Node<$ElementType<T, "payload">>) => string;
(stringifiers: $Exact<$ObjMap<NodeTypes, TypedNodeToStringifier>>);
```
This expresses exactly (heh) the right type.

Test Plan:
Note that removing any of the elements of `NodeTypes` yields a Flow
error, due to the static assertion following the type definition.

wchargin-branch: node-types
This commit is contained in:
William Chargin 2018-03-20 13:27:08 -07:00 committed by GitHub
parent 559ed393a9
commit e9ca833448
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 55 additions and 0 deletions

View File

@ -109,6 +109,61 @@ export type NodeID =
| AuthorNodeID; | AuthorNodeID;
export type NodeType = $ElementType<NodeID, "type">; export type NodeType = $ElementType<NodeID, "type">;
// A map from NodeType string to the corresponding ID and payload types.
// Primarily useful for adding static assertions with $ObjMap, but also
// useful at the value layer as $ElementType<NodeTypes, "ISSUE">, for
// instance.
export type NodeTypes = {|
ISSUE: {
id: IssueNodeID,
payload: IssueNodePayload,
},
PULL_REQUEST: {
id: PullRequestNodeID,
payload: PullRequestNodePayload,
},
COMMENT: {
id: CommentNodeID,
payload: CommentNodePayload,
},
PULL_REQUEST_REVIEW_COMMENT: {
id: PullRequestReviewCommentNodeID,
payload: PullRequestReviewCommentNodePayload,
},
PULL_REQUEST_REVIEW: {
id: PullRequestReviewNodeID,
payload: PullRequestReviewNodePayload,
},
USER: {
id: UserNodeID,
payload: UserNodePayload,
},
ORGANIZATION: {
id: OrganizationNodeID,
payload: OrganizationNodePayload,
},
BOT: {
id: BotNodeID,
payload: BotNodePayload,
},
|};
(function staticAssertions() {
// Check that node payload types are exhaustive.
(x: NodeType): $Keys<NodeTypes> => x;
// Check that each type is associated with the correct ID type.
// Doesn't work because of a Flow bug; should work if that bug is
// fixed: https://github.com/facebook/flow/issues/4211
// (Summary of bug: $ElementType<O, -> does not preserve unions.)
//
// <T: $Keys<NodeTypes>>(
// x: T
// ): $ElementType<
// $ElementType<$ElementType<NodeTypes, T>, "id">,
// "type"
// > => x;
});
export type AuthorshipEdgePayload = {}; export type AuthorshipEdgePayload = {};
export type AuthorshipEdgeID = { export type AuthorshipEdgeID = {
+type: "AUTHORSHIP", +type: "AUTHORSHIP",