Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

openapi-typescript generate enums

given this input:

openapi: 3.0.1
info:
  title: test enums
  description: test enums
  version: "1.00"

components:
  schemas:
    VideoProcessingStateDto:
      type: string
      enum:
        - IN_PROGRESS
        - FAILED
        - FINISHED

I wish to generate the following typescript enum

export enum VideoProcessingStateDto {
  IN_PROGRESS = 'IN_PROGRESS',
  FAILED = 'FAILED',
  FINISHED = 'FINISHED',
}

However, openapi-typescript continues to give me a string union as such:

/** @enum {string} */
VideoProcessingStateDto: "IN_PROGRESS" | "FAILED" | "FINISHED";

Is it possible to configure openapi-typescript to generate enums in this case?

Based on a very superficial glance at the source code, I am not seeing any configuration options

Perhaps I am not defining the enum correctly in the input?

Any guidance would be greatly appreciated, thank you!

like image 640
alex bennett Avatar asked Aug 05 '26 19:08

alex bennett


2 Answers

Following the advanced documentation you can add the --enum flag to the openapi-typescript command and get the enums generated for you without additional effort.

like image 105
naffiq Avatar answered Aug 07 '26 09:08

naffiq


Ok so I decided to engage with the transform option on the API, which allows users to reshape the output as needed. In this case, I am replacing the value with the name of an enum, generating a enum from the values in the union, and adding them to a cache.

When it comes time to output the results to the file, I am then appending the enums to the end of the file so that they exist when they are referenced in the schema components.

This is very rough code and you will probably need to modify it to meet you needs but here is all the code.

import openapiTS, { SchemaObject } from 'openapi-typescript';
import * as fs from 'node:fs';

// Utility function to get the name of the schema from the path
function getSchemaName(str: string) {
  const arr = str.split('/');
  const schemaName = arr[arr.length - 1];
  return schemaName;
}

/** trasform the sting union of "IN_PROGRESS" | "FAILED" | "FINISHED"
 * to a typescript enum like:
 * enum Status {
 * IN_PROGRESS = "IN_PROGRESS",
 * FAILED = "FAILED",
 * FINISHED = "FINISHED"
 * }
 */
function unionToEnum(enumValues: string[], enumName: string) {
  const enumString = enumValues
    .map((value) => `${value} = "${value}"`)
    .join(',\n');
  const enumType = `enum ${enumName} {
    ${enumString}
  }`;
  return enumType;
}

async function generateTypesFromSchema(): Promise<string> {
  const localPath = new URL('api.yml', import.meta.url);
  const output = await openapiTS(localPath, {
    transform: collectAndTransformEnums,
  });
  if (output) {
    return output;
  }
  return '';
}

const enumCache = new Map();

function collectAndTransformEnums(
  schemaObject: SchemaObject,
  metadata: any
): string {
  if ('enum' in schemaObject) {
    const enumName = getSchemaName(metadata.path);
    const enumValues = schemaObject.enum as string[];
    enumCache.set(getSchemaName(enumName), unionToEnum(enumValues, enumName));
    return enumName;
  }
  return '';
}

/**
 * 1. generate the types from the schema
 * 2. iterate over the enumCache and add the enums to the types
 * 3. write the types to a file
 */
generateTypesFromSchema().then((types) => {
  enumCache.forEach((enumType) => {
    types += enumType;
  });

  // write the types to a file
  return fs.writeFile('defs/types.ts', types, (err) => {
    if (err) {
      console.error(err);
      return;
    }
  });
});

Using the script above, given this input:

openapi: 3.0.1

info:
  title: Sample Video API
  description: Sample Video API
  version: '1.0'

paths:
  /api/v1/video-process:
    get:
      tags:
        - video
      summary: Process a video input
      operationId: VideoProcess
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoProcessingStateDto'

components:
  schemas:
    VideoProcessingStateDto:
      type: string
      enum:
        - IN_PROGRESS
        - FAILED
        - FINISHED

The output will be:

/**
 * This file was auto-generated by openapi-typescript.
 * Do not make direct changes to the file.
 */

export interface paths {
  '/api/v1/video-process': {
    /** Process a video input */
    get: operations['VideoProcess'];
  };
}

export type webhooks = Record<string, never>;

export interface components {
  schemas: {
    /** @enum {string} */
    VideoProcessingStateDto: VideoProcessingStateDto;
  };
  responses: never;
  parameters: never;
  requestBodies: never;
  headers: never;
  pathItems: never;
}

export type external = Record<string, never>;

export interface operations {
  /** Process a video input */
  VideoProcess: {
    responses: {
      /** @description Successful operation */
      200: {
        content: {
          'application/json': components['schemas']['VideoProcessingStateDto'];
        };
      };
    };
  };
}
enum VideoProcessingStateDto {
  IN_PROGRESS = 'IN_PROGRESS',
  FAILED = 'FAILED',
  FINISHED = 'FINISHED',
}
like image 45
alex bennett Avatar answered Aug 07 '26 10:08

alex bennett