apollo-tooling
apollo-tooling copied to clipboard
code generator generating strange typescript union types
Intended outcome:
Generating types from a query should not include an "empty" type and union it with the actual requested type.
Actual outcome:
apollo client:codegen
is generating an empty typescript object type. It is then unioned with the requested type from the query.
generated code:
export interface PopularTopicsClients_group_Topic {} // here is the strange "empty" type
export interface PopularTopicsClients_group_Group_featuredTopics_edges_node {
id: string;
}
export interface PopularTopicsClients_group_Group_featuredTopics_edges {
node: PopularTopicsClients_group_Group_featuredTopics_edges_node;
threadCount: number;
}
export interface PopularTopicsClients_group_Group_featuredTopics {
edges: (PopularTopicsClients_group_Group_featuredTopics_edges | null)[];
}
export interface PopularTopicsClients_group_Group {
featuredTopics: PopularTopicsClients_group_Group_featuredTopics;
}
// This unioned type is strange because `PopularTopicsClients_group_Topic` has no fields
// and is not being requested in the query
export type PopularTopicsClients_group = PopularTopicsClients_group_Topic | PopularTopicsClients_group_Group;
export interface PopularTopicsClients {
group: PopularTopicsClients_group | null;
}
export interface PopularTopicsClientsVariables {
first?: number | null;
groupId: string;
}
The strange type is export type PopularTopicsClients_group = PopularTopicsClients_group_Topic | PopularTopicsClients_group_Group;
PopularTopicsClients_group_Topic
is a type with no fields and it's not being requested in the query (see the repro below).
This makes it challenging to use in code because group
is either the fields ive asked for PopularTopicsClients_group_Group
or some empty type. However, this does not match what the server will be returning, nor the structure of the query so it's quite confusing. So using it in code requires a guard:
if (isEmptyType(group)) {
throw new Error('this is just so typescript is happy...');
}
// now group is definitely `PopularTopicsClients_group_Group` so we can access the fields on it
// do stuff with `group.featuredTopics`
How to reproduce the issue:
Use the following schema.graphql
:
interface Node {
id: ID!
}
type Group implements Node {
id: ID!
featuredTopics(
first: Int
): GroupTopicConnection!
}
type Topic implements Node {
id: ID!
}
type GroupTopicConnection {
edges:[GroupTopicEdge]!
pageInfo: PageInfo!
}
type GroupTopicEdge {
node: Topic!
cursor: String!
threadCount: Int!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type Query {
node(
id: ID!
): Node
}
With the following query:
query PopularTopicsClients($first: Int = 5, $groupId: ID!) {
group: node(id: $groupId) {
... on Group {
featuredTopics(first: $first) {
edges {
node {
id
}
threadCount
}
}
}
}
}
Using the following command:
$ npx apollo client:codegen --includes=queryPopularTopics.graphql --target typescript --no-addTypename --localSchemaFile="schema.graphql" --outputFlat src/types --customScalarsPrefix GraphQl --globalTypesFile="src/types/globalTypes.ts"
Versions Tried it on:
apollo/2.30.2 linux-x64 node-v10.22.0
What happens when you remove --no-addTypename
?
I have a similar issue. I believe it has something to do with the fact that you have the Node
type on your RootQueryType that other types inherit from. If you included the __typename
you will probably get a generated PopularTopicsClients_group_Topic
type with the __typename
value being a union type of all the the types that implement node minus the Group
type as it is already generated into one of the possible node types. I am not sure what the solution is however. Did you find a way to resolve this?
I am also interested in finding the solution to this. I would have assumed that the types would only be generated for the requested fragment.
so ...on Group {
should only have types generated for Group and not the other types on the node interface?
Is the answer just to manually check the __typename
?
Is the answer just to manually check the __typename?
That is what I ended up doing. Couldn't find a better way :(
any updates for this?
Hello. Do you guys have a work-around for this?