From e9ca833448b4a1dfa73d3ed5d7df1db1f781efdb Mon Sep 17 00:00:00 2001 From: William Chargin Date: Tue, 20 Mar 2018 13:27:08 -0700 Subject: [PATCH] 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) => string), COMMENT: (stringifyComment: (Node) => string), ... } ``` How do we type this? We might try ```js {[type: NodeType]: (Node) => string} ``` but this is not correct, because `Node` is a subtype of `Node`, and `(_) => K` is contravariant, not covariant. (In other words, a function from `Node` is not as general as a function from `Node`.) We need to express a dependency between the object key and the value. We instead write: ```js type TypedNodeToStringifier = >( T ) => (node: Node<$ElementType>) => string; (stringifiers: $Exact<$ObjMap>); ``` 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 --- src/plugins/github/githubPlugin.js | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/plugins/github/githubPlugin.js b/src/plugins/github/githubPlugin.js index 174ba82..442996e 100644 --- a/src/plugins/github/githubPlugin.js +++ b/src/plugins/github/githubPlugin.js @@ -109,6 +109,61 @@ export type NodeID = | AuthorNodeID; export type NodeType = $ElementType; +// 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, 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 => 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 does not preserve unions.) + // + // >( + // x: T + // ): $ElementType< + // $ElementType<$ElementType, "id">, + // "type" + // > => x; +}); + export type AuthorshipEdgePayload = {}; export type AuthorshipEdgeID = { +type: "AUTHORSHIP",