dotansimha / dotansimha/graphql-code-generator
`typescript-operations` emits an unused schema-types import when fragment types are referenced
- Dominant language
- TypeScript
- Stars
- 11.3k
- Forks
- 1.4k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 23
Description
### Which packages are impacted by your issue?
`@graphql-codegen/typescript-operations`
### Describe the bug
With `importSchemaTypesFrom` and `inlineFragmentTypes: 'combine'`, a document that only *spreads* a
fragment gets an `import type * as Types` it never references. Under `noUnusedLocals` that fails the
build.
## Reproduction
```bash
npm install
npm run generate
npm run typecheck
```
```
src/book.generated.ts(4,1): error TS6133: 'Types' is declared but its value is never read.
```
Two fragments, in separate files. Only `Category` selects the enum field:
```graphql
# src/category.graphql
fragment Category on Category { id kind } # kind: CategoryKind!
# src/book.graphql
fragment Book on Book { id category { ...Category } }
```
`src/category.generated.ts` — import used, correct:
```ts
import type * as Types from '../types';
export type CategoryFragment = { id: string, kind: Types.CategoryKind };
```
`src/book.generated.ts` — import emitted, never referenced:
```ts
import { CategoryFragment } from './category.generated';
import type * as Types from '../types'; // <-- unused
export type BookFragment = { id: string, category: CategoryFragment };
```
## Expected
No `Types` import in `src/book.generated.ts`, since nothing in the file refers to it.
## Cause
`TypeScriptDocumentsVisitor.getExternalSchemaTypeImports()`
(`packages/plugins/typescript/operations/src/visitor.ts`) gates the import on `_usedSchemaTypes`:
```ts
const hasTypesToImport =
Object.values(this._usedSchemaTypes).filter(
value => value.type === 'GraphQLEnumType' || value.type === 'GraphQLInputObjectType',
).length > 0;
if (!hasTypesToImport) {
return [];
}
```
`CategoryKind` is used by the document, so this is `true` for both files. But *used by the document*
and *named by the generated file* are different, and only the second justifies an import.
`_usedSchemaTypes` cannot answer the second on its own: it also decides whether enum and input
definitions are generated locally, which must account for types reached through fragments.
Only `inlineFragmentTypes` decides which of the two applies:
| `inlineFragmentTypes` | `BookFragment` | names `Types`? | `tsc` |
| --- | --- | --- | --- |
| `'inline'` (default) | `{ category: { id: string, kind: Types.CategoryKind } }` | yes | passes |
| `'combine'` | `{ category: CategoryFragment }` | no | **fails** |
### Your Example Website or App
https://stackblitz.com/edit/gdtmg1pc
### Steps to Reproduce the Bug or Issue
Run `npm generate` in the repro
### Expected behavior
It should not have unused imports
### Screenshots or Videos
_No response_
### Platform
| package | version |
| --- | --- |
| `@graphql-codegen/cli` | 7.2.0 |
| `@graphql-codegen/typescript-operations` | 6.1.6 |
| `@graphql-codegen/near-operation-file-preset` | 5.2.2 |
| `graphql` | 16.11.0 |
| `typescript` | 5.9.3 |
### Codegen Config File
```typescript
import type { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: './schema.graphql',
documents: './src/**/*.graphql',
config: {
// Fragment types are referenced, not inlined. This is what makes the bug observable:
// a document that only spreads a fragment never names the schema-types namespace itself.
inlineFragmentTypes: 'combine',
},
generates: {
// Shared Input/Enum types, per the v6 migration guide's multi-file setup.
'./types.ts': {
plugins: ['typescript-operations'],
config: {
generateOperationTypes: false,
},
},
// Per-document operation types, importing the shared types from the file above.
'./src': {
preset: 'near-operation-file',
presetConfig: {
extension: '.generated.ts',
},
plugins: ['typescript-operations'],
config: {
importSchemaTypesFrom: './types.ts',
namespacedImportName: 'Types',
},
},
},
};
export default config;
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in packages/plugins/typescript/operations/src/visitor.ts, especially TypeScriptDocumentsVisitor.getExternalSchemaTypeImports(), and run the reproduction commands npm install, npm run generate, and npm run typecheck. The change is done when inlineFragmentTypes: 'combine' no longer emits an unused Types import for files that only reference a fragment, while the generated types still compile.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, typescript
- Domain
- devtools, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100