Describe the bug
Invalid TypeScript definitions are generated.
export type GetMovieQuery = { node: };
^
To Reproduce
Steps to reproduce the behavior:
type Query {
node(gid: ID!): Node
}
interface Node {
gid: ID!
}
interface Entity {
gid: ID!
active: Boolean!
}
type Movie implements Node, Entity {
gid: ID!
active: Boolean!
name: String!
}
query getMovie($gid: ID!) {
node(gid: $gid) {
... on Entity {
gid
}
}
}
codegen.yml config file:schema: var/schema.json
overwrite: true
generates:
assets/graphql/types.tsx:
documents: 'assets/**/*.gql'
plugins:
- typescript
- typescript-operations
config:
nonOptionalTypename: false
skipTypename: true
preResolveTypes: true
Expected behavior
types.tsx should be a valid TS file.
Environment:
@graphql-codegen/add: 1.8.1@graphql-codegen/cli: 1.8.1@graphql-codegen/fragment-matcher: 1.8.1@graphql-codegen/typescript: 1.8.1@graphql-codegen/typescript-operations: 1.8.1Please note that changing the query to this:
query getMovie($gid: ID!) {
node(gid: $gid) {
gid
... on Entity {
...SomeEntityFragment
}
}
}
Results in this:
export type GetMovieQuery = {
node:
| { gid: string }
| { gid: string }
| { gid: string }
| { gid: string }
| { gid: string }
| { gid: string }
| { gid: string }
| { gid: string }
| { gid: string }
};
Where { gid: string } is produced for each type implementing Node.
Moreover, the fields from SomeEntityFragment are not generated.
When using version 1.7.0 the following type is generated:
export type GetMovieQuery = { node: { } | { } | { } | { } | { } | { } | { } | { } | { } | { } | { } };
I tracked down the bug and it looks like the issue is the 2 interface levels. If I add a new entrypoint:
type Query {
entity(gid: String!): Entity!
}
And change the query to:
fragment EntityBrandActivation on Entity {
gid
brandData(brand: $brand) {
active
}
}
fragment EntityCacheKey on Entity {
... on Company {
id
}
... on Movie {
id
}
... on Series {
id
}
... on Person {
id
}
... on Theater {
id
}
}
query getEntityBrandActivation($gid: ID!, $brand: ID!) {
entity(gid: $gid) {
...EntityBrandActivation
...EntityCacheKey
}
}
Then the generated types are:
export type GetEntityBrandActivationQueryVariables = {
gid: Scalars['ID'],
brand: Scalars['ID']
};
export type GetEntityBrandActivationQuery = { entity: ({ } | { } | { } | { } | { } | { } | { } | { } | { } | { } | { })
// ^^^^
// this is weird
& EntityBrandActivationFragment
& EntityCacheKeyFragment
};
I tried 1.8.2-alpha-a83224e6.9 and a new bug appeared:
export type GetEntityBrandActivationQuery = { entity: (
EntityBrandActivation_User_Fragment
& EntityCacheKey_User_Fragment
) | (
EntityBrandActivation_Company_Fragment
& EntityCacheKey_Company_Fragment
) | (
EntityBrandActivation_Image_Fragment
& EntityCacheKey_Image_Fragment
) | (
EntityBrandActivation_Series_Fragment
& EntityCacheKey_Series_Fragment
) | (
EntityBrandActivation_Person_Fragment
& EntityCacheKey_Person_Fragment
) | (
EntityBrandActivation_Episode_Fragment
& EntityCacheKey_Episode_Fragment
) …
Instead of generating empty objects it now generates fragments. However, some fragment types are not generated which results in an error:
Cannot find name 'EntityCacheKey_Screen_Fragment' .ts(2304)
@ooflorent Any chance you can share a complete schema and queries that reproduces those issues?
Unfortunately I'm not allowed to share this. I'm sorry… Due to the lack of information, I'd understand if you'd want to close the issue. I tried to reproduce the issue by pruning our schema but wasn't able to accurately reproduce the issue.
@ooflorent I really want to solve it :)
Is it possible to share it with type A {} type B {}? only with the minimal types that reproduces the error, I think it's happens because some kind of combination of interfaces and unions.
@ooflorent Can you just share how your types are defined? (for example - type A implements B, interface B, union C = D | A or something similar)
Here is an extract of our schema:
interface Node {
id: ID!
}
scalar DateTime
interface Element {
active: Boolean!
createdAt: DateTime!
createdBy: User
updatedAt: DateTime!
updatedBy: User
}
interface Entity {
brandData(brand: ID!): EntityBrandData
}
type EntityBrandData {
active: Boolean!
description: String!
title: String!
}
type Query {
node(id: ID!): Node!
}
type Company implements Element & Node & Entity {
active: Boolean!
createdAt: DateTime!
createdBy: User
updatedAt: DateTime!
updatedBy: User
id: ID!
brandData(brand: ID!): EntityBrandData
# …
}
type Theater implements Element & Node & Entity {
active: Boolean!
createdAt: DateTime!
createdBy: User
updatedAt: DateTime!
updatedBy: User
id: ID!
brandData(brand: ID!): EntityBrandData
# …
}
type Movie implements Element & Node & Entity {
active: Boolean!
createdAt: DateTime!
createdBy: User
updatedAt: DateTime!
updatedBy: User
id: ID!
brandData(brand: ID!): EntityBrandData
# …
}
type User implements Element & Node & Entity {
active: Boolean!
createdAt: DateTime!
createdBy: User
updatedAt: DateTime!
updatedBy: User
id: ID!
brandData(brand: ID!): EntityBrandData
# …
}
And the query:
query getEntityBrandData($gid: ID!, $brand: ID!) {
node(gid: $gid) {
__typename
id
... on Entity {
...EntityBrandData
}
... on Element {
...ElementMetadata
}
... on Company {
# …
}
... on Theater {
# …
}
}
}
fragment EntityBrandData on Entity {
brandData(brand: $brand) {
active
browsable
title
alternateTitle
description
}
}
fragment ElementMetadata on Element {
createdAt
createdBy {
id
name
}
updatedAt
updatedBy {
id
name
}
}
As you can see, we use a lot the interfaces…
Managed to reproduce it here
@ooflorent I think I managed to fix this issue in: https://github.com/dotansimha/graphql-code-generator/pull/2737
Can you please try the latest alpha? 1.8.2-alpha-9ae02b14.29
Fixed in 1.8.2.