Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit057e156

Browse files
committed
fix: type inference on success calls when not usingwithResponse: true
1 parent0046d5d commit057e156

17 files changed

+79
-64
lines changed

‎.changeset/fluffy-lions-refuse.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"typed-openapi":patch
3+
---
4+
5+
Fix type inference on success calls when not using`withResponse: true` while having multiple responses (ex: one for status 200 and another or status 304) with one that has a resulting schema of`unknown`

‎packages/typed-openapi/src/generator.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ export class ApiClient {
462462
"valibot",
463463
()=>`InferResponseByStatus<${infer(`TEndpoint`)}, SuccessStatusCode>["data"]`,
464464
)
465-
.otherwise(()=>`InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]`)}>;
465+
.otherwise(()=>`Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]`)}>;
466466
467467
${method}<Path extends keyof${capitalizedMethod}Endpoints, TEndpoint extends${capitalizedMethod}Endpoints[Path]>(
468468
path: Path,
@@ -504,7 +504,7 @@ export class ApiClient {
504504
"valibot",
505505
()=>`as Promise<InferResponseByStatus<${infer(`TEndpoint`)}, SuccessStatusCode>["data"]>`,
506506
)
507-
.otherwise(()=>`as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>`)}
507+
.otherwise(()=>`as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>`)}
508508
}
509509
// </ApiClient.${method}>
510510
`

‎packages/typed-openapi/src/tanstack-query.generator.ts‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
9595
withResponse: false as const
9696
};
9797
const res = await this.client.${method}(path, requestParams);
98-
return res as InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"];
98+
return res asExtract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"];
9999
},
100100
queryKey: queryKey
101101
}),
@@ -110,7 +110,7 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
110110
withResponse: false as const
111111
};
112112
const res = await this.client.${method}(path, requestParams);
113-
return res as InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"];
113+
return res asExtract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"];
114114
}
115115
}
116116
};
@@ -134,7 +134,7 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
134134
TWithResponse extends boolean = false,
135135
TSelection = TWithResponse extends true
136136
? InferResponseByStatus<TEndpoint, SuccessStatusCode>
137-
: TEndpoint extends {response: infer Res } ? Res : never,
137+
:Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, {data: {} }>["data"],
138138
TError = TEndpoint extends { responses: infer TResponses }
139139
? TResponses extends Record<string | number, unknown>
140140
? InferResponseByStatus<TEndpoint, ErrorStatusCode>
@@ -144,7 +144,7 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
144144
withResponse?: TWithResponse;
145145
selectFn?: (res: TWithResponse extends true
146146
? InferResponseByStatus<TEndpoint, SuccessStatusCode>
147-
: TEndpoint extends {response: infer Res } ? Res : never
147+
:Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, {data: {} }>["data"]
148148
) => TSelection;
149149
throwOnStatusError?: boolean
150150
}) {
@@ -158,9 +158,7 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
158158
mutationKey: mutationKey,
159159
mutationFn: async <TLocalWithResponse extends boolean = TWithResponse, TLocalSelection = TLocalWithResponse extends true
160160
? InferResponseByStatus<TEndpoint, SuccessStatusCode>
161-
: TEndpoint extends { response: infer Res }
162-
? Res
163-
: never>
161+
: Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>
164162
(params: (TEndpoint extends { parameters: infer Parameters } ? Parameters : {}) & {
165163
withResponse?: TLocalWithResponse;
166164
throwOnStatusError?: boolean;

‎packages/typed-openapi/tests/generator.test.ts‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ describe("generator", () => {
7474
parameters: {
7575
query: Partial<{ status: "available" | "pending" | "sold" }>;
7676
};
77-
responses: { 200: Array<Schemas.Pet>; 400: { code: number; message: string } };
77+
responses: { 200: Array<Schemas.Pet>;304: unknown;400: { code: number; message: string } };
7878
};
7979
export type get_FindPetsByTags = {
8080
method: "GET";
@@ -440,7 +440,7 @@ describe("generator", () => {
440440
put<Path extends keyof PutEndpoints, TEndpoint extends PutEndpoints[Path]>(
441441
path: Path,
442442
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
443-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
443+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
444444
445445
put<Path extends keyof PutEndpoints, TEndpoint extends PutEndpoints[Path]>(
446446
path: Path,
@@ -473,15 +473,15 @@ describe("generator", () => {
473473
return withResponse ? typedResponse : data;
474474
});
475475
476-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
476+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
477477
}
478478
// </ApiClient.put>
479479
480480
// <ApiClient.post>
481481
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
482482
path: Path,
483483
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
484-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
484+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
485485
486486
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
487487
path: Path,
@@ -514,15 +514,15 @@ describe("generator", () => {
514514
return withResponse ? typedResponse : data;
515515
});
516516
517-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
517+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
518518
}
519519
// </ApiClient.post>
520520
521521
// <ApiClient.get>
522522
get<Path extends keyof GetEndpoints, TEndpoint extends GetEndpoints[Path]>(
523523
path: Path,
524524
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
525-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
525+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
526526
527527
get<Path extends keyof GetEndpoints, TEndpoint extends GetEndpoints[Path]>(
528528
path: Path,
@@ -555,15 +555,15 @@ describe("generator", () => {
555555
return withResponse ? typedResponse : data;
556556
});
557557
558-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
558+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
559559
}
560560
// </ApiClient.get>
561561
562562
// <ApiClient.delete>
563563
delete<Path extends keyof DeleteEndpoints, TEndpoint extends DeleteEndpoints[Path]>(
564564
path: Path,
565565
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
566-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
566+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
567567
568568
delete<Path extends keyof DeleteEndpoints, TEndpoint extends DeleteEndpoints[Path]>(
569569
path: Path,
@@ -596,7 +596,7 @@ describe("generator", () => {
596596
return withResponse ? typedResponse : data;
597597
});
598598
599-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
599+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
600600
}
601601
// </ApiClient.delete>
602602
@@ -1116,7 +1116,7 @@ describe("generator", () => {
11161116
get<Path extends keyof GetEndpoints, TEndpoint extends GetEndpoints[Path]>(
11171117
path: Path,
11181118
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
1119-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
1119+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
11201120
11211121
get<Path extends keyof GetEndpoints, TEndpoint extends GetEndpoints[Path]>(
11221122
path: Path,
@@ -1149,7 +1149,7 @@ describe("generator", () => {
11491149
return withResponse ? typedResponse : data;
11501150
});
11511151
1152-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
1152+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
11531153
}
11541154
// </ApiClient.get>
11551155
@@ -1475,7 +1475,7 @@ describe("generator", () => {
14751475
get<Path extends keyof GetEndpoints, TEndpoint extends GetEndpoints[Path]>(
14761476
path: Path,
14771477
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
1478-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
1478+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
14791479
14801480
get<Path extends keyof GetEndpoints, TEndpoint extends GetEndpoints[Path]>(
14811481
path: Path,
@@ -1508,7 +1508,7 @@ describe("generator", () => {
15081508
return withResponse ? typedResponse : data;
15091509
});
15101510
1511-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
1511+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
15121512
}
15131513
// </ApiClient.get>
15141514

‎packages/typed-openapi/tests/map-openapi-endpoints.test.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,9 @@ describe("map-openapi-endpoints", () => {
494494
},
495495
"description": "successful operation",
496496
},
497+
"304": {
498+
"description": "not modified",
499+
},
497500
"400": {
498501
"content": {
499502
"application/json": {
@@ -1544,6 +1547,9 @@ describe("map-openapi-endpoints", () => {
15441547
},
15451548
"description": "successful operation",
15461549
},
1550+
"304": {
1551+
"description": "not modified",
1552+
},
15471553
"400": {
15481554
"content": {
15491555
"application/json": {
@@ -1595,6 +1601,10 @@ describe("map-openapi-endpoints", () => {
15951601
"type": "array",
15961602
"value": "Array<Pet>",
15971603
},
1604+
"304": {
1605+
"type": "keyword",
1606+
"value": "unknown",
1607+
},
15981608
"400": {
15991609
"type": "object",
16001610
"value": "{ code: number, message: string }",

‎packages/typed-openapi/tests/multiple-success-responses.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ describe("multiple success responses", () => {
316316
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
317317
path: Path,
318318
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
319-
): Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
319+
): Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
320320
321321
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
322322
path: Path,
@@ -349,7 +349,7 @@ describe("multiple success responses", () => {
349349
return withResponse ? typedResponse : data;
350350
});
351351
352-
return promise as Promise<InferResponseByStatus<TEndpoint, SuccessStatusCode>["data"]>;
352+
return promise as Promise<Extract<InferResponseByStatus<TEndpoint, SuccessStatusCode>, { data: {} }>["data"]>;
353353
}
354354
// </ApiClient.post>
355355

‎packages/typed-openapi/tests/samples/petstore.yaml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ paths:
147147
type:array
148148
items:
149149
$ref:"#/components/schemas/Pet"
150+
"304":
151+
description:not modified
150152
"400":
151153
description:Invalid status value
152154
content:

‎packages/typed-openapi/tests/snapshots/docker.openapi.client.ts‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,7 +2562,7 @@ export class ApiClient {
25622562
get<PathextendskeyofGetEndpoints,TEndpointextendsGetEndpoints[Path]>(
25632563
path:Path,
25642564
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
2565-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2565+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
25662566

25672567
get<PathextendskeyofGetEndpoints,TEndpointextendsGetEndpoints[Path]>(
25682568
path:Path,
@@ -2595,15 +2595,15 @@ export class ApiClient {
25952595
returnwithResponse ?typedResponse :data;
25962596
});
25972597

2598-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2598+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
25992599
}
26002600
// </ApiClient.get>
26012601

26022602
// <ApiClient.post>
26032603
post<PathextendskeyofPostEndpoints,TEndpointextendsPostEndpoints[Path]>(
26042604
path:Path,
26052605
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
2606-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2606+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
26072607

26082608
post<PathextendskeyofPostEndpoints,TEndpointextendsPostEndpoints[Path]>(
26092609
path:Path,
@@ -2636,15 +2636,15 @@ export class ApiClient {
26362636
returnwithResponse ?typedResponse :data;
26372637
});
26382638

2639-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2639+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
26402640
}
26412641
// </ApiClient.post>
26422642

26432643
// <ApiClient.delete>
26442644
delete<PathextendskeyofDeleteEndpoints,TEndpointextendsDeleteEndpoints[Path]>(
26452645
path:Path,
26462646
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
2647-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2647+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
26482648

26492649
delete<PathextendskeyofDeleteEndpoints,TEndpointextendsDeleteEndpoints[Path]>(
26502650
path:Path,
@@ -2677,15 +2677,15 @@ export class ApiClient {
26772677
returnwithResponse ?typedResponse :data;
26782678
});
26792679

2680-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2680+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
26812681
}
26822682
// </ApiClient.delete>
26832683

26842684
// <ApiClient.put>
26852685
put<PathextendskeyofPutEndpoints,TEndpointextendsPutEndpoints[Path]>(
26862686
path:Path,
26872687
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
2688-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2688+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
26892689

26902690
put<PathextendskeyofPutEndpoints,TEndpointextendsPutEndpoints[Path]>(
26912691
path:Path,
@@ -2718,15 +2718,15 @@ export class ApiClient {
27182718
returnwithResponse ?typedResponse :data;
27192719
});
27202720

2721-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2721+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
27222722
}
27232723
// </ApiClient.put>
27242724

27252725
// <ApiClient.head>
27262726
head<PathextendskeyofHeadEndpoints,TEndpointextendsHeadEndpoints[Path]>(
27272727
path:Path,
27282728
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
2729-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2729+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
27302730

27312731
head<PathextendskeyofHeadEndpoints,TEndpointextendsHeadEndpoints[Path]>(
27322732
path:Path,
@@ -2759,7 +2759,7 @@ export class ApiClient {
27592759
returnwithResponse ?typedResponse :data;
27602760
});
27612761

2762-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
2762+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
27632763
}
27642764
// </ApiClient.head>
27652765

‎packages/typed-openapi/tests/snapshots/long-operation-id.client.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export class ApiClient {
215215
get<PathextendskeyofGetEndpoints,TEndpointextendsGetEndpoints[Path]>(
216216
path:Path,
217217
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
218-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
218+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
219219

220220
get<PathextendskeyofGetEndpoints,TEndpointextendsGetEndpoints[Path]>(
221221
path:Path,
@@ -248,15 +248,15 @@ export class ApiClient {
248248
returnwithResponse ?typedResponse :data;
249249
});
250250

251-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
251+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
252252
}
253253
// </ApiClient.get>
254254

255255
// <ApiClient.post>
256256
post<PathextendskeyofPostEndpoints,TEndpointextendsPostEndpoints[Path]>(
257257
path:Path,
258258
...params:MaybeOptionalArg<TEndpoint["parameters"]&{withResponse?:false;throwOnStatusError?:boolean}>
259-
):Promise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
259+
):Promise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
260260

261261
post<PathextendskeyofPostEndpoints,TEndpointextendsPostEndpoints[Path]>(
262262
path:Path,
@@ -289,7 +289,7 @@ export class ApiClient {
289289
returnwithResponse ?typedResponse :data;
290290
});
291291

292-
returnpromiseasPromise<InferResponseByStatus<TEndpoint,SuccessStatusCode>["data"]>;
292+
returnpromiseasPromise<Extract<InferResponseByStatus<TEndpoint,SuccessStatusCode>,{data:{}}>["data"]>;
293293
}
294294
// </ApiClient.post>
295295

‎packages/typed-openapi/tests/snapshots/petstore.arktype.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export const types = scope({
8989
}),
9090
responses:type({
9191
"200":"Pet[]",
92+
"304":"unknown",
9293
"400":type({
9394
code:"number",
9495
message:"string",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp