-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Which packages are impacted by your issue?
@graphql-codegen/typescript, @graphql-codegen/typescript-operations
Describe the bug
Codegen creates the TypeScript type {}
to represent an empty object, but that is incorrect because in TypeScript that means any types other than null
and undefined
.
The correct type to represent an empty object in TypeScript is { [key: PropertyKey]: never }
(my favourite way) or Record<PropertyKey, never>
.
Deno lint's recommended rule set will actually put a lint error on {}
, via the rule ban-types
:
https://docs.deno.com/lint/rules/ban-types/
Your Example Website or App
Nah
Steps to Reproduce the Bug or Issue
An example of where empty objects can happen in GraphQL operations is:
query Foo {
node(id: "") {
... on User {
__typename
}
}
}
Which will result in something like this:
export type FooQuery = {
readonly node:
| {
readonly __typename: "User";
}
| {}
| null;
};
Because in theory, you could use a node ID for something that's not a User
, and end up with an empty object in the query data.
Expected behavior
Here is a more correct type:
export type FooQuery = {
readonly node:
| {
readonly __typename: "User";
}
| { [key: PropertyKey]: never }
| null;
};
Screenshots or Videos
No response
Platform
- OS: macOS
- Deno: 2.4.2
- @graphql-codegen/cli: 5.0.7
- @graphql-codegen/near-operation-file-preset: 3.1.0
- @graphql-codegen/typescript: 4.1.6
- @graphql-codegen/typescript-operations: 4.6.1
- graphql: 16.11.0
Codegen Config File
In graphql.config.json
:
{
"documents": "**/*.{graphql,mjs}",
"schema": "./schema.graphql",
"extensions": {
"codegen": {
"config": {
"avoidOptionals": true,
"defaultScalarType": "unknown",
"disableDescriptions": true,
"enumsAsTypes": true,
"immutableTypes": true,
"namingConvention": "keep",
"printFieldsOnNewLines": true,
"scalars": {
"Color": "string",
"DateTime": "string",
"Decimal": "string",
"HTML": "string",
"ISO8601DateTime": "string",
"JSON": "string",
"URL": "string",
"UnsignedInt64": "string"
},
"useTypeImports": true
},
"hooks": {
"afterOneFileWrite": ["deno fmt"]
},
"generates": {
"public/types/schema.mts": {
"plugins": ["typescript"],
"config": {
"onlyOperationTypes": true
}
},
"public/": {
"preset": "near-operation-file",
"presetConfig": {
"extension": ".types.mts",
"baseTypesPath": "types/schema.mts.mts"
},
"plugins": ["typescript-operations"],
"config": {
"skipTypename": true
}
}
}
}
}
}
Additional context
A temporary workaround in the codegen config:
{
"hooks": {
"afterOneFileWrite": [
"sed -i '' 's/{}/{ [key: PropertyKey]: never }/g'"
]
}
}