Skip to content

Commit

Permalink
fix(openapi-typescript): handle nullable schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
gduliscouet-ubitransport committed Dec 19, 2024
1 parent ca68475 commit 581e476
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 14 deletions.
25 changes: 11 additions & 14 deletions packages/openapi-typescript/src/transform/schema-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,24 +257,21 @@ export function transformSchemaObjectWithComposition(
}
}

// if final type could be generated, return intersection of all members
if (finalType) {
// deprecated nullable
if (schemaObject.nullable && !schemaObject.default) {
return tsNullable([finalType]);
// When no final type can be generated, fall back to unknown type (or related variants)
if (!finalType) {
if ("type" in schemaObject) {
finalType = tsRecord(STRING, options.ctx.emptyObjectsUnknown ? UNKNOWN : NEVER);
}
return finalType;
}
// otherwise fall back to unknown type (or related variants)
else {
// fallback: unknown
if (!("type" in schemaObject)) {
return UNKNOWN;
else {
finalType = UNKNOWN;
}
}

// if no type could be generated, fall back to “empty object” type
return tsRecord(STRING, options.ctx.emptyObjectsUnknown ? UNKNOWN : NEVER);
if (finalType !== UNKNOWN && schemaObject.nullable && !schemaObject.default) {
finalType = tsNullable([finalType]);
}

return finalType;
}

/**
Expand Down
96 changes: 96 additions & 0 deletions packages/openapi-typescript/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,102 @@ export type operations = Record<string, never>;`,
},
},
],
[
"nullable > basic",
{
given: {
openapi: "3.1",
info: { title: "Test", version: "1.0" },
components: {
schemas: {
NullableEmptyObject: {
nullable: true,
properties: {},
title: "NullableEmptyObject",
type: "object",
},
NullableObject: {
nullable: true,
properties: {
name: {
type: "string",
},
},
title: "NullableObject",
type: "object",
},
NullableString: {
nullable: true,
title: "NullableString",
type: "string",
},
},
},
},
want: `export type paths = Record<string, never>;
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/** NullableEmptyObject */
NullableEmptyObject: Record<string, never> | null;
/** NullableObject */
NullableObject: {
name?: string;
} | null;
/** NullableString */
NullableString: string | null;
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export type operations = Record<string, never>;`,
},
],
[
"nullable > object with ref",
{
given: {
openapi: "3.1",
info: { title: "Test", version: "0" },
components: {
schemas: {
obj1Ref: {
properties: {
id: { type: "string" },
},
},
obj1: {
type: "object",
nullable: true,
$ref: "#/components/schemas/obj1Ref",
},
},
},
paths: {},
},
want: `export type paths = Record<string, never>;
export type webhooks = Record<string, never>;
export interface components {
schemas: {
obj1Ref: {
id?: string;
};
obj1: components["schemas"]["obj1Ref"] | null;
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export type operations = Record<string, never>;`,
},
],
];

for (const [testName, { given, want, options, ci }] of tests) {
Expand Down

0 comments on commit 581e476

Please sign in to comment.