Skip to content

[BUG][TypeScript-Fetch] Incorrect code generation for oneOf schema with number | string types #21259

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

Open
tobq opened this issue May 10, 2025 · 0 comments

Comments

@tobq
Copy link

tobq commented May 10, 2025

The TypeScript-Fetch generator produces incorrect code for a schema that uses oneOf to define a type as either a number or a string. The generated *ToJSONTyped function (e.g., MyCustomSpeedToJSONTyped) returns an empty object {} instead of the actual value when the input value is not null. This leads to incorrect serialization of this type.

The problematic generated code for a type MyCustomSpeed = number | string; is:

/* tslint:disable */
/* eslint-disable */
/**
 * My API
 * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
 *
 * The version of the OpenAPI document: v1
 *
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

/**
 * @type MyCustomSpeed
 * MyCustomSpeed is either a numeric percentage or a predefined string.
 * @export
 */
export type MyCustomSpeed = number | string;

export function MyCustomSpeedFromJSON(json: any): MyCustomSpeed {
    return MyCustomSpeedFromJSONTyped(json, false);
}

export function MyCustomSpeedFromJSONTyped(json: any, ignoreDiscriminator: boolean): MyCustomSpeed {
    if (json == null) {
        return json;
    }
    // The following line is also problematic for FromJSON, it should attempt to parse
    // json as number or string, not return an empty object.
    return {} as any;
}

export function MyCustomSpeedToJSON(value?: MyCustomSpeed | null): any {
    return MyCustomSpeedToJSONTyped(value, false);
}

export function MyCustomSpeedToJSONTyped(value?: MyCustomSpeed | null, ignoreDiscriminator: boolean = false): any {
    if (value == null) {
        return value;
    }
    // This line is incorrect, it should return 'value'
    return {};
}
openapi-generator version

The openapitools.json file indicates version 7.13.0 of generator-cli.

{
  "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
  "spaces": 2,
  "generator-cli": {
    "version": "7.13.0"
  }
}
OpenAPI declaration file content or url

Here's a minimal OpenAPI 3.0 spec to reproduce the issue:

openapi: 3.0.1
info:
  title: Minimal API for Bug Report
  version: v1
paths:
  /test:
    post:
      summary: Test endpoint with MyCustomSpeed
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TestPayload'
      responses:
        '200':
          description: OK
components:
  schemas:
    MyNumericValue:
      type: number
      description: A numeric value (e.g., 0 to 1).
    MyCustomSpeed:
      oneOf:
        - $ref: '#/components/schemas/MyNumericValue'
        - type: string
          enum:
            - "fixed-value-a"
            - "fixed-value-b"
      description: A value that can be a number or a specific string.
    TestPayload:
      type: object
      properties:
        speed_setting:
          $ref: '#/components/schemas/MyCustomSpeed'
Generation Details

The generator is invoked via a script in package.json:

"scripts": {
  "generate-sdk": "openapi-generator-cli generate -i path/to/your/openapi.yml -g typescript-fetch -o output_directory"
}

Replace path/to/your/openapi.yml with the actual path to the OpenAPI spec and output_directory with the desired output folder.

Steps to reproduce
  1. Save the minimal OpenAPI spec above as minimal-openapi.yml.
  2. Ensure you have @openapitools/openapi-generator-cli version 7.13.0 (or potentially other affected versions).
  3. Run the command: openapi-generator-cli generate -i minimal-openapi.yml -g typescript-fetch -o ./generated-sdk
  4. Inspect the generated file generated-sdk/models/MyCustomSpeed.ts.
  5. Observe that MyCustomSpeedToJSONTyped returns {} instead of value.
  6. Observe that MyCustomSpeedFromJSONTyped returns {} instead of attempting to parse the input.
Related issues/PRs

(Please search existing issues on the OpenAPI Generator GitHub repository for similar problems before submitting. If you find any, link them here.)

Suggest a fix

The MyCustomSpeedToJSONTyped function should directly return the value if it's not null, as number and string are already valid JSON types.

export function MyCustomSpeedToJSONTyped(value?: MyCustomSpeed | null, ignoreDiscriminator: boolean = false): any {
    if (value == null) {
        return value;
    }
    // Proposed fix:
    return value;
}

For MyCustomSpeedFromJSONTyped, it needs to correctly handle the oneOf case. Since number and string are primitive types, a simple check should suffice, or it should at least return the input json to be processed by the calling code, rather than an empty object. A more robust solution would be to attempt to match the type.

export function MyCustomSpeedFromJSONTyped(json: any, ignoreDiscriminator: boolean): MyCustomSpeed {
    if (json == null) {
        return json;
    }
    // Proposed fix (simple version, assumes json is already the correct primitive type):
    // More sophisticated type checking could be added if necessary,
    // but for number | string, direct return is often sufficient if upstream validation is done.
    // Alternatively, one could attempt to parse or validate against number and the enum strings.
     if (typeof json === 'number' || typeof json === 'string') { // Add more specific checks for string enums if needed
        return json as MyCustomSpeed;
    }
    // Fallback or error if type doesn't match, instead of empty object
    // For example, throw an error or return the json as is for the caller to handle.
    // Returning json as is:
    return json;
    // Or, to be stricter and closer to typical oneOf handling:
    // try {
    //     // Attempt to validate/deserialize as number
    //     const numVal = MyNumericValueFromJSONTyped(json, true); // Assuming MyNumericValue is just 'number'
    //     return numVal;
    // } catch (e) {
    //     // ignore
    // }
    // try {
    //     // Attempt to validate/deserialize as string enum
    //     if (typeof json === 'string' && (json === "fixed-value-a" || json === "fixed-value-b")) {
    //         return json as string;
    //     }
    // } catch (e) {
    //     // ignore
    // }
    // throw new Error(`No match found in MyCustomSpeedFromJSONTyped for ${JSON.stringify(json)}`);
}

The exact implementation for FromJSONTyped might vary based on how strictly oneOf for primitives should be handled, but returning {} is incorrect. The simplest correct behavior would be return json;.

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

No branches or pull requests

1 participant