openapi-ts / openapi-typescript

Generate TypeScript types from OpenAPI 3 specs
https://openapi-ts.dev
MIT License
5.84k stars 467 forks source link

Enum generation: OpenAPI 3.1 null enum value doesn't generate enum #1872

Open DanDeMicco opened 2 months ago

DanDeMicco commented 2 months ago

Description

A brief description of the bug.

I have a nullable enum yaml file (Open API 3.1) defined like:

type:
  - string
  - 'null'
...
enum:
  - VALUE1
  - VALUE2
  - null

which i have in my schema as

values:
  $ref: <relative_path>/values.yaml

This will output in the TS schema output:

values: "VALUE1" | "VALUE2" | null

with no enum emitted

Name Version
openapi-typescript 7.3.0
Node.js v18.20.4
OS + version macOS 14.6.1

Reproduction

How can this be reproduced / when did the error occur? 1) create a nullable enum similar to the above example, reference it in API 2)

npx openapi-typescript ./openapi.yaml -o ./src/typings/schema.d.ts --enum --alphabetize --dedupe-enums

3) check output schema.d.ts

Expected result 1) It should output the enum for valid values (e.g. export enum Values ... 2) the output in the TS schema should be values: Values | null

Checklist

mchassara commented 4 weeks ago

Hey @DanDeMicco, thank you for submitting an issue. I think I came across the same bug as you (not sure if it is related to this issue though, if not I'll open a new one).

Context

According to OpenAPI specs, nullable enums must contain null value in the enum array as well as nullable: true key/value.

Issue

Using --enum flag and given the following input:

{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "Test": {
        "enum": ["foo", "bar", "baz", null],
        "nullable": true,
        "type": "string"
      }
    }
  }
}

the output TS schema specifies that Test is nullable, but it forgots creating the enum:

export interface components {
    schemas: {
        /** @enum {string|null} */
        Test: "foo" | "bar" | "baz" | null;
    };
    responses: never;
    parameters: never;
    requestBodies: never;
    headers: never;
    pathItems: never;
}

If I don't specify the null value into the enum array, it generates the enum declaration properly but forgets to declare nullable for Test (though the generated doc clearly mention it can be string|null):

export interface components {
    schemas: {
        /** @enum {string|null} */
        Test: Test;
    };
    responses: never;
    parameters: never;
    requestBodies: never;
    headers: never;
    pathItems: never;
}
export enum Test {
    foo = "foo",
    bar = "bar",
    baz = "baz"
}

Expected TS output

The expected TS output would be:

export interface components {
    schemas: {
        Test: Test | null;
    };
    responses: never;
    parameters: never;
    requestBodies: never;
    headers: never;
    pathItems: never;
}
export enum Test {
    foo = "foo",
    bar = "bar",
    baz = "baz"
}

Workaround

However, if we use oneOf mechanism like so:

{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "Test": {
        "anyOf": [
          {
            "enum": ["foo", "bar", "baz"],
            "type": "string"
          },
          {
            "type": "null"
          }
        ]
      }
    }
  }
}

it generates the TS output correctly with both enum declaration and nullable for Test.

Edit

I've tested your fork with the first JSON example I've provided above, and it works like a charm! Thank you ✅