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

`XxMapping` for `discriminator` doesn’t account for `generateUnionEnums`

Open brookjordan opened this issue 1 year ago • 2 comments

Issue

When setting generateUnionEnums to true, the mapping Key generics should be set explicitly as strings rather than using the enum mapping.

Found on version 13.0.3

Setup

That is, in the following situation:

    BranchName:
      type: string
      enum:
        - one
        - two

    Root:
      type: object
      discriminator:
        propertyName: branch
        mapping:
          one: '#/components/schemas/BranchA'
          two: '#/components/schemas/BranchB'
      properties:
        branch:
          $ref: '#/components/schemas/BranchName'

Expected output

export type BranchName = 'one' | 'two';
export type Root = BaseRoot &
  (
    | BaseRootBranchMapping<'one', BranchA>
    | BaseRootBranchMapping<'two', BranchB>
  );

Current output

export type BranchName = 'one' | 'two';
export type Root = BaseRoot &
  (
    | BaseRootBranchMapping<BranchName.One, BranchA>
    | BaseRootBranchMapping<BranchName.Two, BranchB>
  );

Minimal full yaml to reproduce

openapi: 3.0.0
info:
  title: Broken branches
  version: 0.0.0

paths: {}

components:
  schemas:
    BranchName:
      type: string
      enum:
        - one
        - two

    Root:
      type: object
      discriminator:
        propertyName: branch
        mapping:
          one: '#/components/schemas/BranchA'
          two: '#/components/schemas/BranchB'
      properties:
        branch:
          $ref: '#/components/schemas/BranchName'

    BranchA:
      type: object

    BranchB:
      type: object

Expected output:

export type BranchName = 'one' | 'two';

export type Root = BaseRoot & (BaseRootBranchMapping<'one', BranchA> | BaseRootBranchMapping<'two', BranchB>);

export type BranchA = object;

export type BranchB = object;

interface BaseRoot {
  branch?: BranchName;
}

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

Current output:

export type BranchName = 'one' | 'two';

export type Root = BaseRoot &
  (BaseRootBranchMapping<BranchName.One, BranchA> | BaseRootBranchMapping<BranchName.Two, BranchB>);

export type BranchA = object;

export type BranchB = object;

interface BaseRoot {
  branch?: BranchName;
}

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

brookjordan avatar Mar 04 '24 05:03 brookjordan

For anyone needing a workaround until this is fixed, abstracting the discriminator type allows it to work.

For example, it will work correctly if you update the above BranchName type to:

    BranchName:
      allOf:
        - type: string
          enum:
            - one
            - two

brookjordan avatar Mar 04 '24 05:03 brookjordan

Hi, I faced same issue. That workaround did not solve our case. The generated code makes RuleCondition type never as it can never be a string and an enum type at the same time.

export type RuleCondition =
  | ({
      conditionType: "metadataContains";
    } & RuleConditionMetadataContains)
  | ({
      conditionType: "metadataNotContains";
    } & RuleConditionMetadataNotContains)
  | ({
      conditionType: "fieldEquals";
    } & RuleConditionFieldEquals);

export type RuleConditionType = RuleConditionTypeEnum;

/** RuleConditionMetadataContains */
export interface RuleConditionMetadataContains {
  conditionType: RuleConditionType;
  key: string;
  value: string;
}

export enum RuleConditionTypeEnum {
  MetadataContains = "metadataContains",
  MetadataNotContains = "metadataNotContains",
  FieldEquals = "fieldEquals",
}
    RuleCondition:
      title: RuleCondition
      oneOf:
        - $ref: '#/components/schemas/RuleConditionMetadataContains'
        - $ref: '#/components/schemas/RuleConditionMetadataNotContains'
        - $ref: '#/components/schemas/RuleConditionFieldEquals'
      discriminator: 
        propertyName: conditionType
        mapping: 
          metadataContains: '#/components/schemas/RuleConditionMetadataContains'
          metadataNotContains: '#/components/schemas/RuleConditionMetadataNotContains'
          fieldEquals: '#/components/schemas/RuleConditionFieldEquals'
    RuleConditionType:
      allOf:
        - type: string
          enum:
            - metadataContains
            - metadataNotContains
            - fieldEquals

What can be the workaround for our case? Is there a planned fix the problem? Thanks :heart:

nacro90 avatar May 10 '24 11:05 nacro90