Skip to content

Commit 8fb321a

Browse files
authored
fix(typescript-fetch): preserve nullable primitive oneOf branches (#25100)
1 parent 5fbd932 commit 8fb321a

3 files changed

Lines changed: 88 additions & 0 deletions

File tree

‎modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,11 @@ private ExtendedCodegenModel processCodeGenModel(ExtendedCodegenModel cm) {
965965
.map(CodegenComposedSchemas::getOneOf)
966966
.orElse(Collections.emptyList());
967967

968+
// Type names omit branch nullability. Null is valid only when exactly one branch accepts it.
969+
if (oneOfsList.stream().filter(cp -> cp.isNullable).count() == 1) {
970+
cm.oneOf.add("null");
971+
}
972+
968973
// create a set of any non-primitive, non-array types used in the oneOf schemas which will
969974
// need to be imported.
970975
cm.oneOfModels = oneOfsList.stream()

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.openapitools.codegen.typescript.TypeScriptGroups;
1818
import org.openapitools.codegen.utils.ModelUtils;
1919
import org.testng.Assert;
20+
import org.testng.annotations.DataProvider;
2021
import org.testng.annotations.Test;
2122

2223
import java.io.File;
@@ -752,6 +753,38 @@ public void testOneOfModelsDoNotImportPrimitiveTypes() throws IOException {
752753
TestUtils.assertFileContains(testDiscriminatorResponse, "export type TestDiscriminatorResponse = { discriminatorField: 'optionOne' } & OptionOne | { discriminatorField: 'optionTwo' } & OptionTwo");
753754
}
754755

756+
@DataProvider
757+
public Object[][] nullableOneOfRuntimeCheckModes() {
758+
return new Object[][] {{false}, {true}};
759+
}
760+
761+
@Test(dataProvider = "nullableOneOfRuntimeCheckModes")
762+
public void testNullablePrimitiveOneOfTypes(boolean withoutRuntimeChecks) throws IOException {
763+
Map<String, Object> properties = new HashMap<>();
764+
properties.put(TypeScriptFetchClientCodegen.WITHOUT_RUNTIME_CHECKS, withoutRuntimeChecks);
765+
File output = generate(properties,
766+
"src/test/resources/3_0/typescript-fetch/oneof-nullable-primitives.yaml");
767+
768+
for (String model : List.of("InlineNullableValue", "ReferencedNullableValue")) {
769+
Path file = Paths.get(output + (withoutRuntimeChecks ? "/models/index.ts" : "/models/" + model + ".ts"));
770+
TestUtils.assertFileContains(file, "export type " + model + " = null | number | string;");
771+
}
772+
773+
// Null must match exactly one branch, rather than none or both branches.
774+
for (String model : List.of("NonNullableValue", "MultipleNullableValue")) {
775+
Path file = Paths.get(output + (withoutRuntimeChecks ? "/models/index.ts" : "/models/" + model + ".ts"));
776+
TestUtils.assertFileContains(file, "export type " + model + " = number | string;");
777+
}
778+
779+
Path arrayItems = Paths.get(output + (withoutRuntimeChecks
780+
? "/models/index.ts" : "/models/NullableArrayItems.ts"));
781+
TestUtils.assertFileContains(arrayItems, "export type NullableArrayItems = Array<string | null> | number;");
782+
783+
Path values = Paths.get(output + (withoutRuntimeChecks ? "/models/index.ts" : "/models/Values.ts"));
784+
TestUtils.assertFileContains(values, "array: Array<InlineNullableValue>;",
785+
"map: { [key: string]: InlineNullableValue; };");
786+
}
787+
755788
/**
756789
* Issue #21587
757790
* When using oneOf, the Typescript Fetch generator should import modelled types except for
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Nullable primitive oneOf values
4+
version: 1.0.0
5+
paths: {}
6+
components:
7+
schemas:
8+
NullableString:
9+
type: string
10+
nullable: true
11+
InlineNullableValue:
12+
oneOf:
13+
- type: string
14+
nullable: true
15+
- type: number
16+
ReferencedNullableValue:
17+
oneOf:
18+
- $ref: '#/components/schemas/NullableString'
19+
- type: number
20+
NonNullableValue:
21+
oneOf:
22+
- type: string
23+
- type: number
24+
MultipleNullableValue:
25+
oneOf:
26+
- type: string
27+
nullable: true
28+
- type: number
29+
nullable: true
30+
NullableArrayItems:
31+
oneOf:
32+
- type: array
33+
items:
34+
type: string
35+
nullable: true
36+
- type: number
37+
Values:
38+
type: object
39+
required:
40+
- array
41+
- map
42+
properties:
43+
array:
44+
type: array
45+
items:
46+
$ref: '#/components/schemas/InlineNullableValue'
47+
map:
48+
type: object
49+
additionalProperties:
50+
$ref: '#/components/schemas/InlineNullableValue'

0 commit comments

Comments
 (0)