graphql-code-generator: generated type with generic which is never used
Which packages are impacted by your issue?
@graphql-codegen/typescript-resolvers
Describe the bug
It is possible to create a union resolver type which outputs a generic which is not used. The generated code has typescript errors if no-unused-var lint rule is in place.
Your Example Website or App
https://github.com/jaw187/codegen-example
Steps to Reproduce the Bug or Issue
- run
npx graphql-codegenin the example repo - Observe the generated code in
types.tsand note thatRefTypeis not in use
export type ResolversUnionTypes<RefType extends Record<string, unknown>> = {
Foobar: ( Bar ) | ( Foo );
};
Expected behavior
As a user, I expected generated code to be free of reasonable typescript lint errors, but I am seeing no-unused-var errors in the ResolversUnionTypes type.
Screenshots or Videos
Platform
- OS: macOS
- NodeJS: 18.5.0
graphqlversion: 16.6.0@graphql-codegen/add: 5.0.0@graphql-codegen/cli: 4.0.1@graphql-codegen/typescript: 4.0.0@graphql-codegen/typescript-operations: 4.0.0@graphql-codegen/typescript-resolvers: 4.0.0
Codegen Config File
schema: ./*.graphql generates: ./types.ts: plugins: - typescript - typescript-resolvers
Additional context
The example above doesn’t have eslint setup to actually enforce errors. But you can still observe the issue in example.
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 7
- Comments: 18
Hello 👋
noUnusedLocalsandnoUnusedParametersare still linting rules. The difference is that it’s enforced by TypeScript rather than the commonly used ESLint’s counter part, no-unused-var. This means it is still valid TypeScript.Therefore, I recommend not linting the generated types. Here are some options to get around this issue:
Case 1: If you are using both TypeScript and ESLint:
noUnusedLocalsandnoUnusedParametersno-unused-var.eslintignoreto ignore generated files.Case 2: If you are using TypeScript but not ESLint:
// @ts-nocheckat the top of your fileHi @eddeee888, thanks for proposing a solution. Sincerely appreciated.
I’m about to implement it. As I’m in there doing it, a thought has come to mind. Wondering what you thought about it.
I understand your solution to Case 1 technically would solve the issue, but do you think it seems like the solution only ‘sort-of’ fixes the issue?
i.e. in Case 1, it appears the solution you propose leaves the issue in existence and requires consumers of graphql-code-gen in this scenario to re-configure the way they do linting of unused variables.
I understand what you’re saying when you explain that Typescript’s approach to linting with
noUnusedLocalsandnoUnusedParametersis functionally equivalent to using ESLint’s approach to linting withno-unused-var, so that makes sense.What I’m wondering though, wouldn’t it be better for the graphql-code-gen project to instead just not cause the linting issue in the first place? i.e. rather than requiring consumers of graphql-code-gen to have to deal with the issue by re-configuring their own linting configurations, why not just fix the issue at the source and not cause the issue by fixing the fact that
RefTypeis declared but never used?My concern is more about the inconvenience of it. I’m ok dealing with it, but that’s since I managed to find this GH issue report and read through it. What about everyone else that may experience this in the future? Are we just accepting that every single one of them will need to go through the same experience?
i.e. this is now what needs to go in my tsconfig.json file…
I’m ok to go ahead and make the fix on my end, but just thought I’d check to see what you thought of the idea?
Again, thank you, sincerely, for the effort in reading and understanding the issue and for the solution you have proposed. Your effort is very much appreciated. 🙏
@eddeee888 you find me a TS core team member that’ll capitulate to your assertion that those configuration and compilation options are “linting” and I’ll concede that you’re in the right here. Otherwise, my take is that you’re closing and dismissing issues that are actual bugs in codegen. Other teams like https://github.com/drizzle-team/drizzle-orm are on the right side here, and updating their generators to avoid this same situation. Generating code which is not used is a bug, plain and simple.
I see! Unfortunately, it’s not an ESLint rule for me as I am using the following in the tsconfig.json:
As such, no choice but to add
Directly above the line, hence the use of sed!
Thanks for your example dude!
@shellscape here’s my workaround:
@shellscape is right here. This isn’t just a tslint issue, this is a core typescript issue.
The current workaround requires an unnecessary degradation in TS’ safety features.
Understood @eddeee888 , especially about the complexities / opinions associated with linting.
Thanks for your thorough response @eddeee888, I can definitely understand the rationale around trying to keep things lean.
If this is the stance the project is taking, in that case, does it not make sense to bake in the rules that need disabling to the tool itself instead of requiring that users add it themselves?
If we’re essentially saying that graphql-codegen will not support those rules, it makes sense to me that those rules would automatically be disabled in all generated files
Hi @miller-productions and everyone in this thread, 👋
Thanks for taking the time to explain your view of the issue. 🙂
First, this
RefTypegeneric is used in some cases. Here’s a unit test generating the template and here’s the schema for that test. Basically,RefTypeis used to refer back to eitherResolversTypesandResolversParentTypes. (There’s a section at the end with reasoning why the current option was chosen).There are many levels of strictness when it comes to linting in TypeScript projects. If we have to generate code in a way that works for all consumer linting standards, we’d spend a lot more time fixing small linting tweaks, rather than making features.
So, my personal view has been to ignore these files from linting. If it’s valid TypeScript syntax, it’s not a bug.
My opinion about
noUnusedLocalsandnoUnusedParameters:Whether or not codegen is used, I’m against turning on these options and the ESLint rule together. The reason: multiple tools don’t need to be doing the same thing.
So, I don’t think it’s fair to say we have to turn these options off because of codegen. I think it’s a good practice in general. 🙂
Implementation details of why the current solution was chosen
When I was implementing this, there were three options:
ResolversUnionTypesandResolversInterfaceTypesconditionally haveRefTypegeneric, depending on whether it is used in the fields.For example, it may look like this for a simple case:
However, as our schema grows and requires
RefType, it might look like this:This solution is bad because it changes how the generated type works. If this type is imported into other places in the app, it must be updated.
This solution means we’d generate two types like this:
This solution solves the unused variable/param but it means we’d have to run through certain logic multiple times. It also complicates the plugin code a lot more.
This is the current solution. I ultimately went with this because it doesn’t make the plugin logic overly bloated, and it’s still valid TypeScript.
Same problem here.
I’m using the same
@ts-ignoreworkaround for now, but it’s not ideal.I’m also seeing this. @jaw187 do you have any workarounds?
For anyone else wondering, you can just use this script: