Skip to content

Commit 8f6ec20

Browse files
authored
fix: Generate valid types for referenced nested properties (#1743)
1 parent 3a39b68 commit 8f6ec20

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed

.changeset/plenty-islands-tie.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-typescript": patch
3+
---
4+
5+
Generate valid types for referenced nested properties

packages/openapi-typescript/src/lib/ts.ts

+5
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ export function oapiRef(path: string): ts.TypeNode {
122122
);
123123
if (pointer.length > 1) {
124124
for (let i = 1; i < pointer.length; i++) {
125+
// Skip `properties` items when in the middle of the pointer
126+
// See: https://github.com/openapi-ts/openapi-typescript/issues/1742
127+
if (i > 2 && i < pointer.length - 1 && pointer[i] === "properties") {
128+
continue;
129+
}
125130
t = ts.factory.createIndexedAccessTypeNode(
126131
t,
127132
ts.factory.createLiteralTypeNode(

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

+10
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ describe("oapiRef", () => {
6464
test("multiple parts", () => {
6565
expect(astToString(oapiRef("#/components/schemas/User")).trim()).toBe(`components["schemas"]["User"]`);
6666
});
67+
68+
test("removes inner `properties`", () => {
69+
expect(astToString(oapiRef("#/components/schemas/User/properties/username")).trim()).toBe(
70+
`components["schemas"]["User"]["username"]`,
71+
);
72+
});
73+
74+
test("leaves final `properties` intact", () => {
75+
expect(astToString(oapiRef("#/components/schemas/properties")).trim()).toBe(`components["schemas"]["properties"]`);
76+
});
6777
});
6878

6979
describe("tsEnum", () => {

packages/openapi-typescript/test/transform/components-object.test.ts

+54
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,60 @@ describe("transformComponentsObject", () => {
503503
},
504504
},
505505
],
506+
[
507+
"$ref nested properties",
508+
{
509+
given: {
510+
parameters: {
511+
direct: {
512+
name: "direct",
513+
in: "query",
514+
required: true,
515+
schema: {
516+
$ref: "#/components/aaa",
517+
},
518+
},
519+
nested: {
520+
name: "nested",
521+
in: "query",
522+
required: true,
523+
schema: {
524+
$ref: "#/components/schemas/bbb/properties/ccc",
525+
},
526+
},
527+
},
528+
schemas: {
529+
aaa: {
530+
type: "string",
531+
},
532+
bbb: {
533+
type: "object",
534+
properties: {
535+
ccc: {
536+
type: "string",
537+
},
538+
},
539+
},
540+
},
541+
},
542+
want: `{
543+
schemas: {
544+
aaa: string;
545+
bbb: {
546+
ccc?: string;
547+
};
548+
};
549+
responses: never;
550+
parameters: {
551+
direct: components["aaa"];
552+
nested: components["schemas"]["bbb"]["ccc"];
553+
};
554+
requestBodies: never;
555+
headers: never;
556+
pathItems: never;
557+
}`,
558+
},
559+
],
506560
];
507561

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

0 commit comments

Comments
 (0)