apollographql / apollographql/apollo-tooling

code generator generating strange typescript union types

Open
#2,082 6 comments 1 reaction 0 assignees View on GitHub
🤖 component - codegen
Dominant language
TypeScript
Stars
3k
Forks
460
PR merge metrics
No merged PRs in 30d

Description

**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:

```typescript
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:

```typescript
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`:

```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:

```graphql

query PopularTopicsClients($first: Int = 5, $groupId: ID!) {
group: node(id: $groupId) {
... on Group {
featuredTopics(first: $first) {
edges {
node {
id
}
threadCount
}
}
}
}
}
```

Using the following command:

```bash
$ 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`

Contributor guide

Open the contributing guide

Research direction

Start with schema.graphql and queryPopularTopics.graphql, then run the documented apollo client:codegen command against them. Inspect the generated TypeScript for the empty PopularTopicsClients_group_Topic interface and union. Done means the generated group type contains only the requested Group shape, without the empty union member.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.