Skip to content

$defs is getting required part of the schema #2664

Description

@ldrick

openapi-typescript version

7.13.0

Node.js version

24.13.0

OS + version

WSL2 Ubuntu

Description

If you use references "$ref" in one Schema to use reusable fields, these typically recide under "$defs" key.
This "$defs" ends in my Schema and therefore is required for Input using the generated Types. "$defs" is not intended to end up in the Schema as property.

Reproduction

I linted using this command:
pnpm --package=@redocly/cli@latest dlx redocly lint ./demo_api.json
and transformed using this command:
pnpx openapi-typescript "./demo_api.json" --additional-properties --alphabetize --empty-objects-unknown --immutable --output "./demo_api.d.ts"

The Input ("demo_api.json"):

{
    "info": {
        "title": "Test API",
        "version": "1.0.0",
        "license": { "name": "Demo", "url": "https://my.api.com" }
    },
    "openapi": "3.1.2",
    "servers": [{ "url": "https://my.api.com" }],
    "components": {
        "schemas": {
            "InputSchema": {
                "$id": "InputSchema",
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "title": "InputSchema",
                "properties": {
                    "firstname": {
                        "$ref": "#/components/schemas/InputSchema/$defs/firstname"
                    },
                    "lastname": {
                        "$ref": "#/components/schemas/InputSchema/$defs/lastname"
                    }
                },
                "required": [],
                "$defs": {
                    "firstname": {
                        "title": "The Firstname",
                        "type": "string"
                    },
                    "lastname": {
                        "title": "The Lastname",
                        "type": "string"
                    }
                }
            }
        },
        "securitySchemes": {
            "bearerAuth": {
                "bearerFormat": "JWT",
                "scheme": "bearer",
                "type": "http"
            }
        }
    },
    "paths": {
        "/demo": {
            "post": {
                "summary": "Demo",
                "operationId": "demo",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/InputSchema"
                            }
                        }
                    }
                },
                "security": [{ "bearerAuth": [] }]
            }
        }
    }
}

Generates this output ("demo_api.d.ts"):

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

export interface paths {
    readonly "/demo": {
        readonly parameters: {
            readonly query?: never;
            readonly header?: never;
            readonly path?: never;
            readonly cookie?: never;
        };
        readonly get?: never;
        readonly put?: never;
        /** Demo */
        readonly post: operations["demo"];
        readonly delete?: never;
        readonly options?: never;
        readonly head?: never;
        readonly patch?: never;
        readonly trace?: never;
    };
}
export type webhooks = Record<string, never>;
export interface components {
    schemas: {
        /** InputSchema */
        readonly InputSchema: {
            readonly firstname?: components["schemas"]["InputSchema"]["$defs"]["firstname"];
            readonly lastname?: components["schemas"]["InputSchema"]["$defs"]["lastname"];
            $defs: {
                /** The Firstname */
                readonly firstname: string;
                /** The Lastname */
                readonly lastname: string;
            };
        } & {
            readonly [key: string]: unknown;
        };
    };
    responses: never;
    parameters: never;
    requestBodies: never;
    headers: never;
    pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
    readonly demo: {
        readonly parameters: {
            readonly query?: never;
            readonly header?: never;
            readonly path?: never;
            readonly cookie?: never;
        };
        readonly requestBody: {
            readonly content: {
                readonly "application/json": components["schemas"]["InputSchema"];
            };
        };
        readonly responses: never;
    };
}

Expected result

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

export interface paths {
    readonly "/demo": {
        readonly parameters: {
            readonly query?: never;
            readonly header?: never;
            readonly path?: never;
            readonly cookie?: never;
        };
        readonly get?: never;
        readonly put?: never;
        /** Demo */
        readonly post: operations["demo"];
        readonly delete?: never;
        readonly options?: never;
        readonly head?: never;
        readonly patch?: never;
        readonly trace?: never;
    };
}
export type webhooks = Record<string, never>;
export interface components {
    schemas: {
        /** InputSchema */
        readonly InputSchema: {
            readonly firstname?: components["schemas"]["InputSchema"]["$defs"]["firstname"];
            readonly lastname?: components["schemas"]["InputSchema"]["$defs"]["lastname"];
            $defs: {
                /** The Firstname */
                readonly firstname: string;
                /** The Lastname */
                readonly lastname: string;
            };
        } & {
            readonly [key: string]: unknown;
        };
    };
    responses: never;
    parameters: never;
    requestBodies: never;
    headers: never;
    pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
    readonly demo: {
        readonly parameters: {
            readonly query?: never;
            readonly header?: never;
            readonly path?: never;
            readonly cookie?: never;
        };
        readonly requestBody: {
            readonly content: {
                readonly "application/json": Omit<components["schemas"]["InputSchema"], "$defs">;
            };
        };
        readonly responses: never;
    };
}

Required

  • My OpenAPI schema is valid and passes the Redocly validator (npx @redocly/cli@latest lint)

Extra

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingopenapi-tsRelevant to the openapi-typescript library

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions