swagger-typescript-api icon indicating copy to clipboard operation
swagger-typescript-api copied to clipboard

Schema order should not matter

Open dwrBad opened this issue 1 year ago • 0 comments

We are using a type discriminator. The generated types are broken if the schema of that discriminator enum comes after its usage.

Working example

openapi: 3.0.3
info:
  title: example
components:
  schemas:
    DataType:
      type: string
      enum:
        - text
        - number
    ModelField:
      type: object
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextModelField'
      properties:
        type:
          $ref: '#/components/schemas/DataType'
      required:
        - type
    TextModelField:
      description: A data type for representing strings up to 256 characters
      allOf:
        - $ref: '#/components/schemas/ModelField'
        - type: object

results correctly in

export enum DataType {
  Text = "text",
  Number = "number",
}

export type ModelField = BaseModelField & BaseModelFieldTypeMapping<DataType.Text, TextModelField>;

/** A data type for representing strings up to 256 characters */
export type TextModelField = BaseModelField & object;

interface BaseModelField {
  type: DataType;
}

type BaseModelFieldTypeMapping<Key, Type> = {
  type: Key;
} & Type;

Error case

but if I move DataType down:

openapi: 3.0.3
info:
  title: example
components:
  schemas:
    ModelField:
      type: object
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextModelField'
      properties:
        type:
          $ref: '#/components/schemas/DataType'
      required:
        - type
    TextModelField:
      description: A data type for representing strings up to 256 characters
      allOf:
        - $ref: '#/components/schemas/ModelField'
        - type: object
    DataType:
      type: string
      enum:
        - text
        - number

it generates this TS:

export type ModelField = BaseModelField & BaseModelFieldTypeMapping<"text", TextModelField>;

/** A data type for representing strings up to 256 characters */
export type TextModelField = BaseModelField & object;

export enum DataType {
  Text = "text",
  Number = "number",
}

interface BaseModelField {
  type: DataType;
}

type BaseModelFieldTypeMapping<Key, Type> = {
  type: Key;
} & Type;

where let example: ModelField; would resolve to never as textis not the same as DataType.Text

dwrBad avatar Apr 11 '24 10:04 dwrBad