Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird types for schemas with discriminator #1561

Open
zumm opened this issue Jan 13, 2025 · 6 comments
Open

Weird types for schemas with discriminator #1561

zumm opened this issue Jan 13, 2025 · 6 comments
Assignees
Labels
bug 🔥 Something isn't working prioritized 🚚 This issue has been prioritized and will be worked on soon
Milestone

Comments

@zumm
Copy link

zumm commented Jan 13, 2025

Description

For scheme described below openapi-ts generates this code:

export type FeedItem = (({
    type?: 'article';
} & Article) | ({
    type?: 'link';
} & Link)) & {
    type: 'article' | 'link';
};

Shouldn't it be just:

export type FeedItem = (({
    type: 'article';
} & Article) | ({
    type: 'link';
} & Link));

Without third union member and with required type?

Also this scheme causes warning:

Transformers warning: schema {"items":[{"items":[{"properties":{"type":{"const":"article","type":"string"}},"type":"object"},{"$ref":"#/components/schemas/Article"}],"logicalOperator":"and"},{"items":
[{"properties":{"type":{"const":"link","type":"string"}},"type":"object"},{"$ref":"#/components/schemas/Link"}],"logicalOperator":"and"}],"logicalOperator":"or"} is too complex and won't be currently pro
cessed. This will likely produce an incomplete transformer which is not what you want. Please open an issue if you'd like this improved https://github.com/hey-api/openapi-ts/issues

As i understand transformers doesn't work with unions. Could we get discriminated unions supported?

Reproducible example or configuration

No response

OpenAPI specification (optional)

openapi: 3.0.3

paths:
  /feed:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                   $ref: '#/components/schemas/FeedItem'

components:
  schemas:
    FeedItem:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum: [article, link]
      discriminator:
        propertyName: type
        mapping:
          article: '#/components/schemas/Article'
          link: '#/components/schemas/Link'
      oneOf:
        - $ref: '#/components/schemas/Article'
        - $ref: '#/components/schemas/Link'

    Article:
      type: object
      properties:
        id:
          type: integer

    Link:
      type: object
      properties:
        id:
          type: integer

System information (optional)

No response

@zumm zumm added the bug 🔥 Something isn't working label Jan 13, 2025
@mrlubos
Copy link
Member

mrlubos commented Jan 13, 2025

@zumm is this with the experimental parser? https://heyapi.dev/openapi-ts/configuration#parser

@zumm
Copy link
Author

zumm commented Jan 13, 2025

@zumm is this with the experimental parser? https://heyapi.dev/openapi-ts/configuration#parser

Yes, here is my config:

import { defineConfig } from '@hey-api/openapi-ts'

export default defineConfig({
  experimentalParser: true,
  client: '@hey-api/client-fetch',
  input: 'openapi.yaml',
  output: 'api',
  plugins: [{
    name: '@hey-api/transformers',
    dates: true,
  }, {
    name: '@hey-api/sdk',
    transformer: true,
  }, {
    name: '@tanstack/vue-query',
    // @ts-expect-error undocumented feature
    output: 'vue-query',
  }],
})

@mrlubos
Copy link
Member

mrlubos commented Jan 13, 2025

Thanks! I'll have a look

@mrlubos mrlubos added the prioritized 🚚 This issue has been prioritized and will be worked on soon label Jan 13, 2025
@mrlubos mrlubos added this to the Parser milestone Jan 13, 2025
@mrlubos mrlubos self-assigned this Jan 13, 2025
@vst
Copy link

vst commented Jan 23, 2025

Confirming that there is an issue with experimental parser.

Here is my Principal type:

Image

With classic parser, the generated code is:

export type Principal = PrincipalParent | PrincipalStudent;

export type PrincipalParent = {
  type: 'PARENT';
  value: ParentPrincipal;
};

export type PrincipalStudent = {
  type: 'STUDENT';
  value: StudentPrincipal;
};

With experimental parser, the generated code is:

export type Principal =
  | ({
      type?: 'PrincipalParent';
    } & PrincipalParent)
  | ({
      type?: 'PrincipalStudent';
    } & PrincipalStudent);

export type PrincipalParent = {
  type: 'PARENT';
  value: ParentPrincipal;
};

export type PrincipalStudent = {
  type: 'STUDENT';
  value: StudentPrincipal;
};

I did not have time to check the parser code, but it seems that there is some eager logic to encode the discriminator. We may not need explicit discriminators as TS is typed structurally.


PS: There are some issues regarding the error types which are all typed as unknown in my case. It might be related to something else. So, let me save you from details.

@mrlubos
Copy link
Member

mrlubos commented Jan 23, 2025

@vst If you can share the relevant parts of your spec, that would be appreciated!

@vst
Copy link

vst commented Jan 23, 2025

@mrlubos Sure. Sorry, it took a while to extract the relevant part.

Let me know if you need more.

openapi: 3.0.0
info:
  title: API Documentation
  version: 0.0.21
components:
  schemas:
    EmailAddress:
      type: string
    ParentId:
      description: |-
        AuthUser Identifier.
        Type representing Universally Unique Identifiers (UUID) as specified in RFC 4122.
      type: string
    ParentPrincipal:
      properties:
        email:
          $ref: '#/components/schemas/EmailAddress'
        emailVerifiedAt:
          description: |-
            Parent email verified at.
            UTCTime
          nullable: true
          type: string
        id:
          $ref: '#/components/schemas/ParentId'
        username:
          description: Parent username.
          type: string
      required:
        - id
        - email
        - username
        - emailVerifiedAt
      type: object
    Principal:
      discriminator:
        mapping:
          PARENT: PrincipalParent
          STUDENT: PrincipalStudent
        propertyName: type
      oneOf:
        - $ref: '#/components/schemas/PrincipalParent'
        - $ref: '#/components/schemas/PrincipalStudent'
    PrincipalParent:
      properties:
        type:
          enum:
            - PARENT
          type: string
        value:
          $ref: '#/components/schemas/ParentPrincipal'
      required:
        - value
        - type
      type: object
    PrincipalStudent:
      properties:
        type:
          enum:
            - STUDENT
          type: string
        value:
          $ref: '#/components/schemas/StudentPrincipal'
      required:
        - value
        - type
      type: object
    StudentId:
      description: |-
        AuthUser Identifier.
        Type representing Universally Unique Identifiers (UUID) as specified in RFC 4122.
      type: string
    StudentPrincipal:
      properties:
        email:
          $ref: '#/components/schemas/EmailAddress'
        emailVerifiedAt:
          description: |-
            Student email verified at.
            UTCTime
          nullable: true
          type: string
        id:
          $ref: '#/components/schemas/StudentId'
        username:
          description: Student username.
          type: string
      required:
        - id
        - email
        - username
        - emailVerifiedAt
      type: object
paths:
  /me:
    get:
      description: This endpoint returns principal information.
      responses:
        '200':
          content:
            application/json;charset=utf-8:
              schema:
                $ref: '#/components/schemas/Principal'
          description: ''
        '401':
          description: Authentication failed
        '403':
          description: Authorization failed
      summary: Principal Endpoint

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🔥 Something isn't working prioritized 🚚 This issue has been prioritized and will be worked on soon
Projects
None yet
Development

No branches or pull requests

3 participants