Skip to content

$defs is getting required part of the schema #2664

@ldrick

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

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