Skip to content

useImplementingTypes generates incorrect code due to missing parentheses around ternaries joined with || #200

@lucastraba

Description

@lucastraba

Describe the bug

When useImplementingTypes is enabled and an interface has 2 or more implementing types, the generated mock code joins ternary expressions with || without wrapping each ternary in parentheses. Because || has higher precedence than ?: in JavaScript/TypeScript, the resulting expression is parsed incorrectly.

Generated (broken):

event: relationshipsToOmit.has('MeetingEvent') ? {} as MeetingEvent : mockMeetingEvent({}, relationshipsToOmit) || relationshipsToOmit.has('OtherEvent') ? {} as OtherEvent : mockOtherEvent({}, relationshipsToOmit)

JavaScript parses this as:

relationshipsToOmit.has('MeetingEvent')
  ? {} as MeetingEvent
  : (mockMeetingEvent({}, relationshipsToOmit) || relationshipsToOmit.has('OtherEvent'))
      ? {} as OtherEvent
      : mockOtherEvent({}, relationshipsToOmit)

Because mockMeetingEvent({}, relationshipsToOmit) returns a truthy object, the || short-circuits, and the second ternary's truthy branch ({} as OtherEvent) is always selected — meaning you always get an empty shell object instead of a real mock for the second (and subsequent) implementing types.

Expected (correct):

event: (relationshipsToOmit.has('MeetingEvent') ? {} as MeetingEvent : mockMeetingEvent({}, relationshipsToOmit)) || (relationshipsToOmit.has('OtherEvent') ? {} as OtherEvent : mockOtherEvent({}, relationshipsToOmit))

Your Example Website or App

No response

Steps to Reproduce the Bug or Issue

  1. Define a GraphQL schema with an interface that has 2+ implementing types
  2. Configure the plugin with useImplementingTypes: true (the issue is worse with terminateCircularRelationships: true since the ternaries are more complex, but it affects both paths)
  3. Generate mocks
  4. Observe that fields typed as the interface always resolve to {} as SecondType instead of a real mock

Minimal schema:

interface Event {
  startDate: String
}

type MeetingEvent implements Event {
  startDate: String
  event: Event!
}

type OtherEvent implements Event {
  startDate: String
  somethingElse: String!
}

Expected behavior

Each implementing type's ternary expression should be wrapped in parentheses before being joined with ||, so that operator precedence is correct and each type's mock is independently evaluated.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • NodeJS: 22.x
  • graphql-codegen-typescript-mock-data: latest (v3.x)

Codegen Config File

No response

Additional context

The fix is a one-line change in src/index.ts in the case 'implement': block — add .map((v) => '(' + v + ')') before .join(' || ').

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions