Skip to content

Commit 82a7fba

Browse files
author
Gregory Haddow
committed
fix: correctly type response when there is a 204 in addition to another 2xx response
1 parent 7d94cc7 commit 82a7fba

3 files changed

Lines changed: 63 additions & 12 deletions

File tree

plugins/typescript/src/core/getDataResponseType.test.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe("getDataResponseType", () => {
3030
},
3131
};
3232

33-
const responseType = getDataResponseType({
33+
const [responseType] = getDataResponseType({
3434
responses,
3535
printNodes: (nodes) => nodes.map(print).join("\n"),
3636
});
@@ -68,7 +68,7 @@ describe("getDataResponseType", () => {
6868
},
6969
};
7070

71-
const responseType = getDataResponseType({
71+
const [responseType] = getDataResponseType({
7272
responses,
7373
printNodes: (nodes) => nodes.map(print).join("\n"),
7474
});
@@ -106,7 +106,7 @@ describe("getDataResponseType", () => {
106106
},
107107
};
108108

109-
const responseType = getDataResponseType({
109+
const [responseType] = getDataResponseType({
110110
responses,
111111
printNodes: (nodes) => nodes.map(print).join("\n"),
112112
});
@@ -119,11 +119,39 @@ describe("getDataResponseType", () => {
119119
it("should returns undefined when no response", () => {
120120
const responses: ResponsesObject = {};
121121

122-
const responseType = getDataResponseType({
122+
const [responseType] = getDataResponseType({
123123
responses,
124124
printNodes: (nodes) => nodes.map(print).join("\n"),
125125
});
126126

127127
expect(print(responseType)).toMatchInlineSnapshot(`"undefined"`);
128128
});
129+
130+
it("should union undefined when also a 204 response", () => {
131+
const responses: ResponsesObject = {
132+
"200": {
133+
description: "pet response",
134+
content: {
135+
"application/json": {
136+
schema: {
137+
type: "array",
138+
items: {
139+
$ref: "#/components/schemas/Pet",
140+
},
141+
},
142+
},
143+
},
144+
},
145+
"204": {
146+
description: "no content",
147+
},
148+
};
149+
150+
const [responseType, has204] = getDataResponseType({
151+
responses,
152+
printNodes: (nodes) => nodes.map(print).join("\n"),
153+
});
154+
expect(has204).toBe(true);
155+
expect(print(responseType)).toMatchInlineSnapshot(`"Schemas.Pet[]"`);
156+
});
129157
});

plugins/typescript/src/core/getDataResponseType.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,24 @@ export const getDataResponseType = ({
2323
responses?: ResponsesObject;
2424
components?: ComponentsObject;
2525
printNodes: (nodes: ts.Node[]) => string;
26-
}) => {
26+
}): [ts.TypeNode, boolean] => {
2727
if (responses === undefined) {
28-
return f.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword);
28+
return [f.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword), false];
2929
}
30+
let has204 = false;
3031
const responseTypes = uniqBy(
3132
Object.entries(responses).reduce(
3233
(
3334
mem,
3435
[statusCode, response]: [string, ResponseObject | ReferenceObject],
3536
) => {
3637
if (!statusCode.startsWith("2")) return mem;
38+
39+
if (statusCode === "204") {
40+
has204 = true;
41+
return mem;
42+
}
43+
3744
if (isReferenceObject(response)) {
3845
const [hash, topLevel, namespace, name] = response.$ref.split("/");
3946
if (hash !== "#" || topLevel !== "components") {
@@ -74,9 +81,11 @@ export const getDataResponseType = ({
7481
(node) => printNodes([node]),
7582
);
7683

77-
return responseTypes.length === 0
78-
? f.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
79-
: responseTypes.length === 1
80-
? responseTypes[0]
81-
: f.createUnionTypeNode(responseTypes);
84+
const responseType =
85+
responseTypes.length === 0
86+
? f.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
87+
: responseTypes.length === 1
88+
? responseTypes[0]
89+
: f.createUnionTypeNode(responseTypes);
90+
return [responseType, has204 && responseTypes.length > 0];
8291
};

plugins/typescript/src/core/getOperationTypes.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,13 @@ export const getOperationTypes = ({
5151
const declarationNodes: ts.Node[] = [];
5252

5353
// Retrieve dataType
54-
let dataType = getDataResponseType({
54+
const dataTypeTuple = getDataResponseType({
5555
responses: operation.responses,
5656
components: openAPIDocument.components,
5757
printNodes,
5858
});
59+
let dataType = dataTypeTuple[0];
60+
const has204 = dataTypeTuple[1];
5961

6062
// Retrieve errorType
6163
let errorType = getErrorResponseType({
@@ -159,6 +161,18 @@ export const getOperationTypes = ({
159161
dataType = f.createTypeReferenceNode(dataTypeIdentifier);
160162
}
161163

164+
if (has204) {
165+
dataType = ts.isUnionTypeNode(dataType)
166+
? f.createUnionTypeNode([
167+
...dataType.types,
168+
f.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
169+
])
170+
: f.createUnionTypeNode([
171+
dataType,
172+
f.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
173+
]);
174+
}
175+
162176
// Export requestBody type if needed
163177
if (shouldExtractNode(requestBodyType)) {
164178
const requestBodyIdentifier = pascal(`${operationId}RequestBody`);

0 commit comments

Comments
 (0)