openapi-typescript
openapi-typescript copied to clipboard
Self referential types fail to compile
Description
Having a self referential type like...
"Json": {
"anyOf": [
{
"type": "string"
},
{
"type": "number",
"format": "double"
},
{
"type": "boolean"
},
{
"properties": {},
"additionalProperties": {
"$ref": "#/components/schemas/Json"
},
"type": "object"
},
{
"items": {
"$ref": "#/components/schemas/Json"
},
"type": "array"
}
],
"nullable": true
},
Causes typescript to be generate like this
export interface components {
schemas: {
Json: (string | number | boolean | {
[key: string]: components["schemas"]["Json"];
} | components["schemas"]["Json"][]) | null;
Causing this failure...
./lib/clients/jawnTypes.ts:34:5
Type error: 'Json' is referenced directly or indirectly in its own type annotation.
32 | phoneNumbers: string[];
33 | };
> 34 | Json: (string | number | boolean | {
| ^
35 | [key: string]: components["schemas"]["Json"];
36 | } | components["schemas"]["Json"][]) | null;
37 | /** @enum {string} */
Name | Version |
---|---|
openapi-typescript |
6.7.5 |
Node.js | 18.17.1 |
OS + version | macOS 14.3 |
Reproduction
wget https://raw.githubusercontent.com/Helicone/helicone/53cbb77419d533bbe20de8262a3887786e3c0faa/valhalla/jawn/src/tsoa-build/swagger.json
openapi-typescript swagger.json -o types.ts
Expected result
We can somehow build the typescript to move any self-referential types to it's own type like this?
type JsonValue = string | number | boolean | null | JsonArray | JsonObject;
interface JsonArray extends Array<JsonValue> {}
interface JsonObject {
[key: string]: JsonValue;
}
export interface components {
schemas: {
User: {
/** Format: double */
id: number;
email: string;
name: string;
/** @enum {string} */
status?: "Happy" | "Sad";
/** @enum {string} */
status2?: "Happy" | "Sad";
phoneNumbers: string[];
};
Json: JsonObject;
Checklist
- [ ] My OpenAPI schema passes the Redocly validator (
npx @redocly/cli@latest lint
) - [x] I’m willing to open a PR (see CONTRIBUTING.md)
Similar problem here. The (reduced) code looks like this:
PackageTreePermittedResponseV2: WithRequired<{
permission: "FULL";
} & Omit<components["schemas"]["PackageTreeResponseV2"], "permission"> & ({
packages?: components["schemas"]["PackageTreeResponseV2"][];
}), "id" | "permission" | "packages">;
PackageTreeResponseV2: {
id: string;
permission: string;
} & (components["schemas"]["PackageTreePermittedResponseV2"]);
Errors:
TS2502: PackageTreePermittedResponseV2 is referenced directly or indirectly in its own type annotation.
TS2502: PackageTreeResponseV2 is referenced directly or indirectly in its own type annotation.
"PackageTreePermittedResponseV2": {
"required": [
..........................................................
"id",
"packages",
"permission",
..........................................................
],
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/PackageTreeResponseV2"
},
{
"type": "object",
"properties": {
..........................................................
"packages": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PackageTreeResponseV2"
}
},
..........................................................
}
}
]
},
"PackageTreeResponseV2": {
"title": "PackageTreeResponseV2",
"required": ["id", "permission"],
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"permission": {
"type": "string"
}
},
"discriminator": {
"propertyName": "permission",
"mapping": {
"FULL": "#/components/schemas/PackageTreePermittedResponseV2",
..........................................................
}
},
"oneOf": [
{
"$ref": "#/components/schemas/PackageTreePermittedResponseV2"
},
{
"$ref": "#/components/schemas/PackageTreeUnauthorisedResponseV2"
}
]
},