Skip to content

Commit 581e476

Browse files
fix(openapi-typescript): handle nullable schemas
1 parent ca68475 commit 581e476

File tree

2 files changed

+107
-14
lines changed

2 files changed

+107
-14
lines changed

packages/openapi-typescript/src/transform/schema-object.ts

+11-14
Original file line numberDiff line numberDiff line change
@@ -257,24 +257,21 @@ export function transformSchemaObjectWithComposition(
257257
}
258258
}
259259

260-
// if final type could be generated, return intersection of all members
261-
if (finalType) {
262-
// deprecated nullable
263-
if (schemaObject.nullable && !schemaObject.default) {
264-
return tsNullable([finalType]);
260+
// When no final type can be generated, fall back to unknown type (or related variants)
261+
if (!finalType) {
262+
if ("type" in schemaObject) {
263+
finalType = tsRecord(STRING, options.ctx.emptyObjectsUnknown ? UNKNOWN : NEVER);
265264
}
266-
return finalType;
267-
}
268-
// otherwise fall back to unknown type (or related variants)
269-
else {
270-
// fallback: unknown
271-
if (!("type" in schemaObject)) {
272-
return UNKNOWN;
265+
else {
266+
finalType = UNKNOWN;
273267
}
268+
}
274269

275-
// if no type could be generated, fall back to “empty object” type
276-
return tsRecord(STRING, options.ctx.emptyObjectsUnknown ? UNKNOWN : NEVER);
270+
if (finalType !== UNKNOWN && schemaObject.nullable && !schemaObject.default) {
271+
finalType = tsNullable([finalType]);
277272
}
273+
274+
return finalType;
278275
}
279276

280277
/**

packages/openapi-typescript/test/index.test.ts

+96
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,102 @@ export type operations = Record<string, never>;`,
694694
},
695695
},
696696
],
697+
[
698+
"nullable > basic",
699+
{
700+
given: {
701+
openapi: "3.1",
702+
info: { title: "Test", version: "1.0" },
703+
components: {
704+
schemas: {
705+
NullableEmptyObject: {
706+
nullable: true,
707+
properties: {},
708+
title: "NullableEmptyObject",
709+
type: "object",
710+
},
711+
NullableObject: {
712+
nullable: true,
713+
properties: {
714+
name: {
715+
type: "string",
716+
},
717+
},
718+
title: "NullableObject",
719+
type: "object",
720+
},
721+
NullableString: {
722+
nullable: true,
723+
title: "NullableString",
724+
type: "string",
725+
},
726+
},
727+
},
728+
},
729+
want: `export type paths = Record<string, never>;
730+
export type webhooks = Record<string, never>;
731+
export interface components {
732+
schemas: {
733+
/** NullableEmptyObject */
734+
NullableEmptyObject: Record<string, never> | null;
735+
/** NullableObject */
736+
NullableObject: {
737+
name?: string;
738+
} | null;
739+
/** NullableString */
740+
NullableString: string | null;
741+
};
742+
responses: never;
743+
parameters: never;
744+
requestBodies: never;
745+
headers: never;
746+
pathItems: never;
747+
}
748+
export type $defs = Record<string, never>;
749+
export type operations = Record<string, never>;`,
750+
},
751+
],
752+
[
753+
"nullable > object with ref",
754+
{
755+
given: {
756+
openapi: "3.1",
757+
info: { title: "Test", version: "0" },
758+
components: {
759+
schemas: {
760+
obj1Ref: {
761+
properties: {
762+
id: { type: "string" },
763+
},
764+
},
765+
obj1: {
766+
type: "object",
767+
nullable: true,
768+
$ref: "#/components/schemas/obj1Ref",
769+
},
770+
},
771+
},
772+
paths: {},
773+
},
774+
want: `export type paths = Record<string, never>;
775+
export type webhooks = Record<string, never>;
776+
export interface components {
777+
schemas: {
778+
obj1Ref: {
779+
id?: string;
780+
};
781+
obj1: components["schemas"]["obj1Ref"] | null;
782+
};
783+
responses: never;
784+
parameters: never;
785+
requestBodies: never;
786+
headers: never;
787+
pathItems: never;
788+
}
789+
export type $defs = Record<string, never>;
790+
export type operations = Record<string, never>;`,
791+
},
792+
],
697793
];
698794

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

0 commit comments

Comments
 (0)