Graphql-code-generator: TypeScript Generated Definition Contains More Than Just What Queried

Created on 14 Jul 2020  路  15Comments  路  Source: dotansimha/graphql-code-generator

Describe the bug
When performing a generation of TypeScript from a schema that is a file to a document that contain only a subset of all the type in the schema, the generated TypeScript contains all the type of the schema instead of only the subset used in the document.

To Reproduce
Configuration of codegen.yml

schema: "./allSchema.graphql"
documents: "./oneFieldQuery.graphql"
overwrite: true
generates:
    ./generated/mytype.ts:
        config:
            maybeValue: T | undefined
            preResolveTypes: true
            avoidOptionals: true
        plugins:
            - typescript
            - typescript-operations
            - add:
                  content:
                      - "/* tslint:disable */"
require: ["ts-node/register"]

Environment:

  • OS: MacOS
  • @graphql-codegen/...: Tried with 1.15 and 1.17
  • NodeJS: v14.4.0
waiting-for-answer

All 15 comments

Thanks for taking the time to open this issue! This is currently working as intended. You can set the onlyOperationTypes option to true to only generate only the minimum number of types necessary.

Hi Daniel,
I set the onlyOperationTypes and the output does not change. (Same as if not provided)

image

For example, I see a lot of enum that I do not use in the simple query. I am query 1 field (ID) from 1 entity. And I have about 100+ type generated.

This is with onlyOperationTypes: true in the config

This is the current implementation, it's basically ignores all schema parts except enums and input types because those might be needed by operation.
I think we can maybe improve the implementation to really include only what's used.

Btw, @MrDesjardins, what's your actual use-case? Why is it a problem that you have those enums generated? Because if it's not needed, maybe you can remove it from the schema?

Hi,
Interesting! Thank you for the clarification.

My use case was that two people added the same enum in GraphQL. The generation caused issues because two keys were the same value. That change caused my generation to fail. However, I do not use that enum... it shouldn't affect my code base :)

E.g.

Person 1:

enum TestEnum {
Field1 = "A"
}

Person 2 (somewhere else in another .graphql file)

enum TestEnum {
Field1 = "a"
}

The generation is

Export enum TestEnum {
Field1 = "a",
Field1 = "A"
}

It does not compile :)

@MrDesjardins I think it should have break before codegen... it doesn't make any sense to have duplicate key in enums.

If it's an issue with the generated types and not with the schema, some developers find this useful:

namingConvention:
  enumValues: keep

It will make sure to keep keys as is and won't change enum keys like _A to A

Clear the generated file to include only what is used would be great

@dotansimha I think it should have break before codegen... it doesn't make any sense to have duplicate key in enums.

Well, in real life it does make sense and does not break before.

For example, you are using serviceA and serviceB. The first service is very old and used a different format than the new shinny service B. However, A and B are required because the shinny new B does not have everything yet. With that scenario, you can have from both the same enum with different upper/lower case. It does not break. GraphQL can fetch both service, and the person who use the serviceB added the enum with the casing as the service was returning it, same for the other engineer for the serviceA.

@carlosfiori I can edit the generated file manually, it fixes the issue. But, editing the generated type would be a chore and open a door to potential error.

Let me try the enumValues:keep and see what is happening.

@MrDesjardins Can you please explain? maybe I'm missing something, but how does it make sense for the same enum to have a duplicate key ?
The example you shared, creates a TestEnum twice, with the same key called Field1. This should never compile, in any language - either GraphQL or TypeScript. Different cases are different keys - field1 and Field1 are totally different keys, and it's not a duplicate key at all.

If you have different casing- use enumValues: keep - it will work are won't apply any string manipulation over the enums keys.

Hello,

you please explain?

Let's step back.

Engineer 1 working on project A
Engineer 2 working on project B

The project A has in the codebase has a GraphQL file with

enum TestEnum {
Field1 = "A"
}

It compiles, it is legit. It's GraphQL.

The project B has in the codebase has a GraphQL file with

enum TestEnum {
Field1 = "a"
}

At that point, both projects compile. It is totally legit.

maybe I'm missing something, but how does it make sense for the same enum to have a duplicate key ?

We combine both types from project A and B together to have a Graph of both system.

E.g. by doing:

import path from "path";
import { fileLoader, mergeTypes } from "merge-graphql-schemas";
const typesArray = fileLoader(path.join(__dirname, "/**/*.graphql"));
const mergeSchemaTypes = mergeTypes(typesArray);

We have a legit GraphQL file:

enum TestEnum {
  a
  A
}

At that point, the TypeScript project compiles. The GraphQL has two same entry. One lower case, one upper case.

Now, I am using code-gen and I have the generated fault TypeScript:

export enum TestEnum {
    A = "A",
    A = "a",
}

So, the GraphQL wasn't causing issue on each project. The merge was not causing the issue. The issue started when we used code-gen to generate the TypeScript for that particular case.

So, the case is possible. I know the "best practice" is to have all the enum value in uppercase and I have remedied the situation. However, there is (IMO) a flaw to rely on that practice since many legacy systems might not be under the upper case principle. :)

I have quickly looked at the enum: keep but I had a lot of error saying "Cannot find module "keep" to its corresponding type declaration. I'll have to check that out Monday.

Have a good weekend!

I see, and I understood your example, but it's just incorrect.

Combining these two enums:

# 1
enum TestEnum {
Field1 = "A"
}

# 2
enum TestEnum {
Field1 = "a"
}

Will create this enum:

enum TestEnum {
Field1 = "A"
Field1 = "a"
}

Which is an error, because Field1 is a duplicate key. If the keys of enum are duplicated, it's an error. I guess you refer to this result:

enum TestEnum {
  A,
  a
}

Which is different, because keys are unique.

Also, in GraphQL SDL, the = form isn't a valid way to declare an enum (Syntax Error: Expected Name, found "=". ), so I'm not sure how it works.

To fix that in codegen output, add this configuration:

config:
  namingConvention:
    enumValues: 'keep'

My example is auto-generated. It might be "incorrect", but the merge of the enum is creating that duplication of keys.

Here is a reproduction test.

Run :

npm install
npm gen

Open the file types.d.ts and scroll to line 13:

image

The

  namingConvention:
    enumValues: 'keep'

Is fixing the issue. Might want to add some documentation for that scenario or having code-gen give a warning that suggests that fix.

Thanks!

I just found out that I forgot to push the repository with the reproduction:

https://github.com/MrDesjardins/code-gen-duplicate

npm install
npm gen

@MrDesjardins I'm closing for now, opened a new ticket for tracking the improvement of onlyOperationTypes here: https://github.com/dotansimha/graphql-code-generator/issues/4562

@dotansimha to pile on to the use case here, for large federated graphs, my total file size generated is nearing 2MB. The number of exports and types seems like it puts an unnecessary strain on the TS compiler and IDE.

This combination:

      preResolveTypes: true
      onlyOperationTypes: true

is useful and has significantly reduced my file size, but it's still generating all enum and input types in the graph

Was this page helpful?
0 / 5 - 0 ratings