Skip to content

TypeScript output shouldn't treat interface as a union of implementing types #5869

Open
@twavv

Description

@twavv

Is your feature request related to a problem? Please describe.

The current treatment of interfaces treats an interface as a union of its types. This means it's actually not safe for backwards compatible usage (i.e., the server should be able to add new interface implementations in a backwards compatible way, but graphql-code-generator breaks that contract). It's not the end of the world, but I didn't see anything else about this.

Describe the solution you'd like

It's not possible to do something like

interface IAnimal { __typename: string; name: string; }
interface Dog extends IAnimal { __typename: "Dog"; favoriteDogTreatType: string; }
interface Cat extends IAnimal { __typename: "Cat"; meowVolume: number; }

since the resulting codegen would be something like this:

type Animal = IAnimal | Dog | Cat;

and this would be broken:

const animal: IAnimal = ...;
if (animal.__typename === "Dog") {
  // This is an error since this type guard only narrows to (IAnimal | Dog)
  // since it's technically valid for IAnimal to have __typename "Dog" in
  // TypeScript's world -- even though that's not possible in GraphQL world
  console.log(animal.favoriteDogTreatType);
}

One solution to this could be to use a sentinel value:

type Animal = (IAnimal & __typename: "_interface_sentinel_do_not_check_for_me_or_you_will_be_fired_") | Dog | Cat;

Describe alternatives you've considered
Status quo isn't the end of the world! :)

Additional context

The actual issues this can cause is essentially forgetting to write fallback code which then breaks when new interface implementations are added on the server side.

// This type-checks in the current version
function greetAnimal(animal: Animal): string {
  switch (animal.__typename) {
  case "Dog":
    return `Hello, puppy!`;
  case "Cat":
    return `Meow meow.`;
  }
}

This breaks when the server adds an Iguana implementation because there's no default case.

Metadata

Metadata

Assignees

Labels

coreRelated to codegen core/clikind/enhancementNew feature or requeststage/0-issue-prerequisitesNeeds more information before we can start working on itstatus/triageIssue to be reviewed and actioned upon

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions