apollo-tooling
apollo-tooling copied to clipboard
[Flow] Export each possible variant of a union as a separate type
When I generate flow types for the following query:
query.graphql
query contentQuery {
helpDocs_Content {
__typename
... on HelpDocs_Faq {
id
question
answer
}
... on HelpDocs_Tutorial {
id
title
introduction
conclusion
}
}
}
Based on the following schema:
schema.graphql
type HelpDocs_Faq {
id: ID!
question: String!
answer: String!
}
type HelpDocs_Tutorial {
id: ID!
title: String!
introduction: String!
conclusion: String!
}
union HelpDocs_Content =
HelpDocs_Faq
| HelpDocs_Tutorial
type Query {
helpDocs_Content(slug: String!): HelpDocs_Content
}
I get the following types:
types.js
export type contentQuery_helpDocs_Content = {
__typename: "HelpDocs_Faq",
id: string,
question: string,
answer: string,
} | {
__typename: "HelpDocs_Tutorial",
id: string,
title: string,
introduction: string,
conclusion: string,
};
export type contentQuery = {
helpDocs_Content: ?contentQuery_helpDocs_Content
};
In my code, I can use __typename
to tell which variant I got and as long as I do that before using a field that is not found in all types, Flow will accept that:
if (obj.__typename === 'HelpDocs_Faq') {
console.log(obj.question);
}
However, if I pass the data down to another function I'd still need to test for the __typename
there as well:
function handleFaq(obj: contentQuery_helpDocs_Content) {
// $FlowFixMe
console.log(obj.question);
}
if (obj.__typename === 'HelpDocs_Faq') {
handleFaq(obj);
}
What I'd like for codegen to generate instead is:
export type contentQuery_helpDocs_Content_HelpDocs_Faq = {
__typename: "HelpDocs_Faq",
id: string,
question: string,
answer: any,
};
export type contentQuery_helpDocs_Content_HelpDocs_Tutorial = {
__typename: "HelpDocs_Tutorial",
id: string,
title: string,
introduction: any,
conclusion: any,
};
export type contentQuery_helpDocs_Content =
contentQuery_helpDocs_Content_HelpDocs_Faq
| contentQuery_helpDocs_Content_HelpDocs_Tutorial;
export type contentQuery = {
helpDocs_Content: ?contentQuery_helpDocs_Content
};
That way, I can use the variant types in the function without further checks, as Flow can see that what I pass to the function is the type it expects and within the function, it can rely on getting that type only.
function handleFaq(obj: contentQuery_helpDocs_Content_HelpDocs_Faq) {
console.log(obj.question);
}
if (obj.__typename === 'HelpDocs_Faq') {
handleFaq(obj);
}
This is a great suggestion 👍 I'd be very open to a PR that implements this! Happy to provide guidance to anyone interested.
For reference; I opened a similar issue for graphql-code-generator.com: https://github.com/dotansimha/graphql-code-generator/issues/1870
Also need this.