Describe the bug
Queries for interfaces do not have to correct typename.
If you have an Interface, e.g. Person, which is used by a type, e.g Actor, querying Person will resolve into typenames with Actor.
Actual Output
export type PersonByNameQuery = (
{ __typename?: 'Query' }
& { Person?: Maybe<Array<Maybe<(
{ __typename?: 'Actor' }
& Pick<Actor, 'uuid' | 'name'>
)>>> }
);
Expected Output
export type PersonByNameQuery = (
{ __typename?: 'Query' }
& { Person?: Maybe<Array<Maybe<(
{ __typename?: 'Person' }
& Pick<Person, 'uuid' | 'name'>
)>>> }
);
To Reproduce
Use the schema, operations and config at live-example
Sandbox doesn't seem to work atm.
schema {
query: Query
}
interface Person {
uuid: ID!
name: String!
}
type Actor implements Person {
uuid: ID!
name: String!
}
type Query {
Person(name: String): [Person]
@cypher(statement: """
MATCH
(a:Person)
WHERE a.name = $name
RETURN a
""")
}
query PersonByName($payload: String!) {
Person(name: $payload) {
uuid
name
}
}
codegen.yml config file:generates:
types.ts:
plugins:
- typescript
- typescript-operations
Expected behavior
Environment:
@graphql-codegen/latest: Hi @hrzwkstim01. Thanks for opening an issue.
This is working as expected. __typename will always resolve to the name of the actual object type returned at runtime. It can never return the name of an abstract type. So if you have a Person interface that's extended by Actor or Director, when querying a field that returns a Person, the __typename will always be either Actor or Director. The same is true for union types, which are also an abstract type like interfaces.
If you add another type that implements person, you'll see the generated type reflects both possible __typename values, in addition to the fields specific to each type:
export type PersonByNameQuery = (
{ __typename?: 'Query' }
& { Person?: Maybe<Array<Maybe<(
{ __typename?: 'Actor' }
& Pick<Actor, 'uuid' | 'name'>
) | (
{ __typename?: 'Director' }
& Pick<Director, 'uuid' | 'name'>
)>>> }
);
@danielrearden
Thanks for the rapid answer and explanation!
I was expecting that abstracted classes can also be resolved.
For instance, the neo4j-graphql library is treating queries/mutaiton with interfaces the same as with types, resulting to have Actor or Director nodes also to have a label of Person.
That way I can easily query for the union of Actors and Directors via Person.
That happens if two instances have different views of abstraction 馃槃
Cheers
Most helpful comment
Hi @hrzwkstim01. Thanks for opening an issue.
This is working as expected.
__typenamewill always resolve to the name of the actual object type returned at runtime. It can never return the name of an abstract type. So if you have aPersoninterface that's extended byActororDirector, when querying a field that returns aPerson, the__typenamewill always be eitherActororDirector. The same is true for union types, which are also an abstract type like interfaces.If you add another type that implements person, you'll see the generated type reflects both possible
__typenamevalues, in addition to the fields specific to each type: