Skip to content
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

Enum names are not preserved #30

Open
javibookline opened this issue Nov 28, 2022 · 5 comments · Fixed by Darius-Labs/pydantic-to-typescript2#3
Open

Enum names are not preserved #30

javibookline opened this issue Nov 28, 2022 · 5 comments · Fixed by Darius-Labs/pydantic-to-typescript2#3

Comments

@javibookline
Copy link

Enums which are part of a pydantic model are translated to a type, losing relevant and useful information that could be kept if they were translated to enums in typescript too

@robbieaverill
Copy link

This is most likely a duplicate of #15

@kevinhikaruevans
Copy link

+1.

This would be nice considering I'm using enum names in backend and I would prefer not to use just the enum values in my frontend (which are nearly meaningless without the names).

@guaycuru
Copy link

guaycuru commented Sep 20, 2024

@robbieaverill I don't think this is a duplicate of #15

Currently it works like this, it converts:

class Status(str, Enum):
    active = "active"
    inactive = "inactive"

class SomeSchema(BaseSchema):
    id: UUID
    status: Status

To:

export type Status = "active" | "inactive";

export interface SomeSchema {
  id: string;
  status: Status;
}

Which means we can't use Status.active in our TS code.
But if instead it was converted like this:

export enum Status {
    active = "active",
    inactive = "inactive",
}

export interface SomeSchema {
  id: string;
  status: Status;
}

We could use Status.active in TS code

@guaycuru
Copy link

Apparently this is possible starting from json-schema-to-typescript v14.1+. Just add the --inferStringEnumKeysFromValues flag to the json2ts command line.

@ahhmino
Copy link

ahhmino commented Dec 12, 2024

I'm adding my solution to this problem as well, since I also needed enum keys to be persisted during the generation:

Using the --inferStringEnumKeysFromValues flag does help initially, so that this Python enum:

class A(enum.Enum):
    A = 'value_a'
    B = 'value_b'

Then generates

export enum A { 
    value_a = 'value_a'
    value_b = 'value_b'
}

But I needed the following

export enum A {
    A = 'value_a'
    B = 'value_b'
}

So I threw together a short script to find and replace those enums in the generated file. Note that this only works without the inferStringEnumKeysFromValues flag enabled. Doesn't handle nested schema directories, but did the job for me, hopefully useful for someone else:

import enum
import importlib
import os
import inspect
import re

from pydantic2ts import generate_typescript_defs

# Module of the file containing schema to generate in TS
schema_module = 'api.src.schemas'

# Output TS file path
models_file_path = './frontend/src/models.d.ts'

# Directory containing all Python schemas
schemas_dir = './api/src'

# Module containing all Python schemas
schemas_module = 'api.src'

generate_typescript_defs(schema_module, models_file_path, (),
                         'json2ts --enableConstEnums false '
                         '--unreachableDefinitions true --strictIndexSignatures true')

enums = {}
for file_name in os.listdir(schemas_dir):
    if file_name.endswith(".py") and file_name != "__init__.py":
        module_name = file_name[:-3]  # Remove the '.py' extension
        module = importlib.import_module(f'{schemas_module}.{module_name}')

        # Find all Enum subclasses in the module
        for name, obj in inspect.getmembers(module):
            if inspect.isclass(obj) and issubclass(obj, enum.Enum):
                enums[name] = obj


with open(models_file_path, 'r') as models_file:
    models = models_file.read()
    for name, obj in enums.items():
        new_enum_values = ",\n  ".join([f'{member.name} = "{member.value}"' for member in obj])
        new_enum = f'export enum {name} {{\n  {new_enum_values}\n}}'
        models = re.sub(rf'export type {name} [^;]*;', new_enum, models, flags=re.S | re.M)

with open(models_file_path, 'w') as models_file:
    models_file.write(models)

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

Successfully merging a pull request may close this issue.

5 participants