Skip to content

Commit 784169c

Browse files
Goldziherprovinzkraut
authored andcommitted
fix: typescript export not handling NotRequired and regression with handling of additional_properties (#4318)
* chore: handle additional properties causing schema == None * fix: make properties optional when no required fields specified When schema.required is None or empty, properties should default to optional rather than required. This fixes NotRequired TypedDict fields not being converted to optional TypeScript properties with '?'. * chore: updated test (cherry picked from commit a43525b)
1 parent 42a89e0 commit 784169c

2 files changed

Lines changed: 59 additions & 55 deletions

File tree

litestar/_openapi/typescript_converter/schema_parsing.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def create_interface(
9494
TypeScriptProperty(
9595
key=normalize_typescript_namespace(key, allow_quoted=True),
9696
value=parse_schema(schema),
97-
required=key in required if required is not None else True,
97+
required=key in required if required is not None else False,
9898
)
9999
for key, schema in properties.items()
100100
)
@@ -124,6 +124,10 @@ def parse_type_schema(schema: Schema) -> TypeScriptPrimitive | TypeScriptLiteral
124124
)
125125
if schema.type in openapi_to_typescript_type_map and isinstance(schema.type, OpenAPIType):
126126
return TypeScriptPrimitive(openapi_to_typescript_type_map[schema.type])
127+
if schema.type is None:
128+
# Handle schemas with no type specified (e.g., additional_properties that can contain any value)
129+
# According to OpenAPI spec, a schema without a type can contain any JSON value
130+
return TypeScriptPrimitive("any")
127131
raise TypeError(f"received an unexpected openapi type: {schema.type}") # pragma: no cover
128132

129133

tests/unit/test_openapi/test_typescript_converter/test_converter.py

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,17 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe
6969
7070
export namespace Http201 {
7171
export type ResponseBody = {
72-
complex: {
72+
complex?: {
7373
7474
};
75-
first_name: string;
76-
id: string;
77-
last_name: string;
78-
optional: null | string;
79-
pets: null | {
80-
age: number;
81-
name: string;
82-
species: "Cat" | "Dog" | "Monkey" | "Pig";
75+
first_name?: string;
76+
id?: string;
77+
last_name?: string;
78+
optional?: null | string;
79+
pets?: null | {
80+
age?: number;
81+
name?: string;
82+
species?: "Cat" | "Dog" | "Monkey" | "Pig";
8383
}[];
8484
}[];
8585
};
@@ -97,17 +97,17 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe
9797
};
9898
9999
export type RequestBody = {
100-
complex: {
100+
complex?: {
101101
102102
};
103-
first_name: string;
104-
id: string;
105-
last_name: string;
106-
optional: null | string;
107-
pets: null | {
108-
age: number;
109-
name: string;
110-
species: "Cat" | "Dog" | "Monkey" | "Pig";
103+
first_name?: string;
104+
id?: string;
105+
last_name?: string;
106+
optional?: null | string;
107+
pets?: null | {
108+
age?: number;
109+
name?: string;
110+
species?: "Cat" | "Dog" | "Monkey" | "Pig";
111111
}[];
112112
}[];
113113
};
@@ -119,17 +119,17 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe
119119
120120
export namespace Http200 {
121121
export type ResponseBody = {
122-
complex: {
122+
complex?: {
123123
124124
};
125-
first_name: string;
126-
id: string;
127-
last_name: string;
128-
optional: null | string;
129-
pets: null | {
130-
age: number;
131-
name: string;
132-
species: "Cat" | "Dog" | "Monkey" | "Pig";
125+
first_name?: string;
126+
id?: string;
127+
last_name?: string;
128+
optional?: null | string;
129+
pets?: null | {
130+
age?: number;
131+
name?: string;
132+
species?: "Cat" | "Dog" | "Monkey" | "Pig";
133133
}[];
134134
}[];
135135
};
@@ -147,17 +147,17 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe
147147
};
148148
149149
export type RequestBody = {
150-
complex: {
150+
complex?: {
151151
152152
};
153-
first_name: string;
154-
id: string;
155-
last_name: string;
156-
optional: null | string;
157-
pets: null | {
158-
age: number;
159-
name: string;
160-
species: "Cat" | "Dog" | "Monkey" | "Pig";
153+
first_name?: string;
154+
id?: string;
155+
last_name?: string;
156+
optional?: null | string;
157+
pets?: null | {
158+
age?: number;
159+
name?: string;
160+
species?: "Cat" | "Dog" | "Monkey" | "Pig";
161161
}[];
162162
}[];
163163
};
@@ -396,17 +396,17 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe
396396
export namespace ServiceIdPersonPersonIdPartialUpdatePerson {
397397
export namespace Http200 {
398398
export type ResponseBody = {
399-
complex: {
399+
complex?: {
400400
401401
};
402-
first_name: string;
403-
id: string;
404-
last_name: string;
405-
optional: null | string;
406-
pets: null | {
407-
age: number;
408-
name: string;
409-
species: "Cat" | "Dog" | "Monkey" | "Pig";
402+
first_name?: string;
403+
id?: string;
404+
last_name?: string;
405+
optional?: null | string;
406+
pets?: null | {
407+
age?: number;
408+
name?: string;
409+
species?: "Cat" | "Dog" | "Monkey" | "Pig";
410410
}[];
411411
};
412412
};
@@ -425,17 +425,17 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe
425425
};
426426
427427
export type RequestBody = {
428-
complex: {
428+
complex?: {
429429
430430
};
431-
first_name: string;
432-
id: string;
433-
last_name: string;
434-
optional: null | string;
435-
pets: null | {
436-
age: number;
437-
name: string;
438-
species: "Cat" | "Dog" | "Monkey" | "Pig";
431+
first_name?: string;
432+
id?: string;
433+
last_name?: string;
434+
optional?: null | string;
435+
pets?: null | {
436+
age?: number;
437+
name?: string;
438+
species?: "Cat" | "Dog" | "Monkey" | "Pig";
439439
}[];
440440
};
441441
};

0 commit comments

Comments
 (0)