Skip to content

[WIP] Fix generated schemas for oneOf types to preserve type discriminators#3296

Closed
Copilot wants to merge 1 commit intomainfrom
copilot/fix-oneof-type-discriminator-values
Closed

[WIP] Fix generated schemas for oneOf types to preserve type discriminators#3296
Copilot wants to merge 1 commit intomainfrom
copilot/fix-oneof-type-discriminator-values

Conversation

Copy link
Contributor

Copilot AI commented Feb 2, 2026

Thanks for assigning this issue to me. I'm starting to work on it and will keep this PR's description up to date as I form a plan and make progress.

Original prompt

This section details on the original issue you should resolve

<issue_title>Write schemas generated for oneOf types override type discriminator values</issue_title>
<issue_description>### Description

When @hey-api/openapi-ts generates TypeScript types from an OpenAPI spec containing polymorphic types with readOnly properties, it creates "Writable" variants with incorrect typeDiscriminator values.

The generated types use a PascalCase discriminator derived from the type name (e.g., 'DogPayloadWritable') instead of preserving the discriminator value from the OpenAPI spec (e.g., 'dog').

This causes deserialization failures in the backend that still expects the original type discriminators it has defined.

Interestingly enough, this issue wasn't present in @hey-api/openapi-ts 0.84.4, which I suppose might have been due to writable types not being generated properly with polymorphic types so this bug never surfaced itself because of that.

Reproducible example or configuration

Environment

  • @hey-api/openapi-ts: v0.90.10
  • Backend: ASP.NET Core with System.Text.Json
  • OpenAPI generator: Swashbuckle

Reproduction

.NET models

[JsonPolymorphic(TypeDiscriminatorPropertyName = "typeDiscriminator")]
[JsonDerivedType(typeof(DogPayload), "dog")]
[JsonDerivedType(typeof(CatPayload), "cat")]
public abstract record AnimalPayload;

public record DogPayload : AnimalPayload
{
    public required string Breed { get; init; }
    public required bool CanFetch { get; init; }

    /// Computed property - marked as readOnly in OpenAPI schema.
    /// This triggers hey-api to generate a Writable variant.
    public string DisplayBreed => $"{Breed} (Dog)";
}

public record CatPayload : AnimalPayload
{
    public required string Breed { get; init; }
    public required int LivesRemaining { get; init; }

    /// Computed property - marked as readOnly in OpenAPI schema.
    /// This triggers hey-api to generate a Writable variant.
    public string DisplayBreed => $"{Breed} (Cat)";
}

public record CreatePetRequest
{
    public required string Name { get; init; }
    public required AnimalPayload Animal { get; init; }
}

Generated TS Read types (correct)

export type DogPayload = Omit<AnimalPayload, 'typeDiscriminator'> & {
  breed: string
  canFetch: boolean
  readonly displayBreed: string
  typeDiscriminator: 'dog'  // Correct - matches OpenAPI spec
}

export type CatPayload = Omit<AnimalPayload, 'typeDiscriminator'> & {
  breed: string
  livesRemaining: number
  readonly displayBreed: string
  typeDiscriminator: 'cat'  // Correct - matches OpenAPI spec
}

Generated TS Writable types (incorrect):

export type DogPayloadWritable = Omit<AnimalPayload, 'typeDiscriminator'> & {
  breed: string
  canFetch: boolean
  typeDiscriminator: 'DogPayloadWritable'  // should be 'dog'
}

export type CatPayloadWritable = Omit<AnimalPayload, 'typeDiscriminator'> & {
  breed: string
  livesRemaining: number
  typeDiscriminator: 'CatPayloadWritable'  // should be 'cat'
}

export type CreatePetRequestWritable = {
  name: string
  animal: DogPayloadWritable | CatPayloadWritable  // Uses wrong discriminators
}

OpenAPI specification (optional)

OpenAPI Schema (Backend)

components:
  schemas:
    AnimalPayload:
      type: object
      required: [typeDiscriminator]
      properties:
        typeDiscriminator:
          type: string
      discriminator:
        propertyName: typeDiscriminator
        mapping:
          dog: '#/components/schemas/DogPayload'
          cat: '#/components/schemas/CatPayload'

    DogPayload:
      allOf:
        - $ref: '#/components/schemas/AnimalPayload'
        - type: object
          required: [breed, canFetch, displayBreed]
          properties:
            breed:
              type: string
            canFetch:
              type: boolean
            displayBreed:
              type: string
              readOnly: true  # <-- This triggers Writable variant generation

    CatPayload:
      allOf:
        - $ref: '#/components/schemas/AnimalPayload'
        - type: object
          required: [breed, livesRemaining, displayBreed]
          properties:
            breed:
              type: string
            livesRemaining:
              type: integer
            displayBreed:
              type: string
              readOnly: true  # <-- This triggers Writable variant generation

    CreatePetRequest:
      type: object
      required: [name, animal]
      properties:
        name:
          type: string
        animal:
          oneOf:
            - $ref: '#/components/schemas/DogPayload'
            - $ref: '#/components/schemas/CatPayload'

System information (optional)

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@vercel
Copy link

vercel bot commented Feb 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hey-api-docs Ready Ready Preview, Comment Feb 2, 2026 9:45pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 2, 2026

⚠️ No Changeset found

Latest commit: 97669b3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write schemas generated for oneOf types override type discriminator values

2 participants