@@ -29,31 +29,51 @@ export type OpArgType<OP> = OP extends {
2929 ? P & Q & ( B extends Record < string , unknown > ? B [ keyof B ] : unknown ) & RB
3030 : Record < string , never >
3131
32- export type OpDefaultReturnType < OP > = OP extends {
33- responses : {
34- default : infer D
35- }
32+ type OpResponseTypes < OP > = OP extends {
33+ responses : infer R
3634}
37- ? D extends { schema : infer S }
38- ? S
39- : D extends { content : { 'application/json' : infer C } } // openapi 3
40- ? C
41- : D
35+ ? {
36+ [ S in keyof R ] : R [ S ] extends { schema ?: infer S } // openapi 2
37+ ? S
38+ : R [ S ] extends { content : { 'application/json' : infer C } } // openapi 3
39+ ? C
40+ : S extends 'default'
41+ ? R [ S ]
42+ : unknown
43+ }
44+ : never
45+
46+ type _OpReturnType < T > = 200 extends keyof T
47+ ? T [ 200 ]
48+ : 'default' extends keyof T
49+ ? T [ 'default' ]
4250 : unknown
4351
44- export type OpReturnType < OP > = OP extends {
45- responses : {
46- 200 : {
47- schema ?: infer R
48- // openapi 3
49- content ?: {
50- 'application/json' : infer C
51- }
52- }
52+ export type OpReturnType < OP > = _OpReturnType < OpResponseTypes < OP > >
53+
54+ type _OpDefaultReturnType < T > = 'default' extends keyof T
55+ ? T [ 'default' ]
56+ : unknown
57+
58+ export type OpDefaultReturnType < OP > = _OpDefaultReturnType < OpResponseTypes < OP > >
59+
60+ // private symbol to prevent narrowing on "default" error status
61+ const never : unique symbol = Symbol ( )
62+
63+ type _OpErrorType < T > = {
64+ [ S in Exclude < keyof T , 200 > ] : {
65+ status : S extends 'default' ? typeof never : S
66+ data : T [ S ]
5367 }
54- }
55- ? R & C
56- : OpDefaultReturnType < OP >
68+ } [ Exclude < keyof T , 200 > ]
69+
70+ type Coalesce < T , D > = [ T ] extends [ never ] ? D : T
71+
72+ // coalesce default error type to unknown
73+ export type OpErrorType < OP > = Coalesce <
74+ _OpErrorType < OpResponseTypes < OP > > ,
75+ unknown
76+ >
5777
5878export type CustomRequestInit = Omit < RequestInit , 'headers' > & {
5979 readonly headers : Headers
@@ -64,18 +84,32 @@ export type Fetch = (
6484 init : CustomRequestInit ,
6585) => Promise < ApiResponse >
6686
67- export type TypedFetch < R , A > = (
68- arg : A ,
87+ export type _TypedFetch < OP > = (
88+ arg : OpArgType < OP > ,
6989 init ?: RequestInit ,
70- ) => Promise < ApiResponse < R > >
90+ ) => Promise < ApiResponse < OpReturnType < OP > > >
91+
92+ export type TypedFetch < OP > = _TypedFetch < OP > & {
93+ Error : new ( error : ApiError ) => ApiError & {
94+ getActualType : ( ) => OpErrorType < OP >
95+ }
96+ }
97+
98+ export type FetchArgType < F > = F extends TypedFetch < infer OP >
99+ ? OpArgType < OP >
100+ : never
71101
72- export type FetchArgType < F > = F extends TypedFetch < any , infer A > ? A : never
102+ export type FetchReturnType < F > = F extends TypedFetch < infer OP >
103+ ? OpReturnType < OP >
104+ : never
73105
74- export type FetchReturnType < F > = F extends TypedFetch < infer R , any > ? R : never
106+ export type FetchErrorType < F > = F extends TypedFetch < infer OP >
107+ ? OpErrorType < OP >
108+ : never
75109
76110type _CreateFetch < OP , Q = never > = [ Q ] extends [ never ]
77- ? ( ) => TypedFetch < OpReturnType < OP > , OpArgType < OP > >
78- : ( query : Q ) => TypedFetch < OpReturnType < OP > , OpArgType < OP > >
111+ ? ( ) => TypedFetch < OP >
112+ : ( query : Q ) => TypedFetch < OP >
79113
80114export type CreateFetch < M , OP > = M extends 'post' | 'put' | 'patch' | 'delete'
81115 ? OP extends { parameters : { query : infer Q } }
@@ -121,7 +155,7 @@ export class ApiError extends Error {
121155 readonly statusText : string
122156 readonly data : any
123157
124- constructor ( response : ApiResponse ) {
158+ constructor ( response : Omit < ApiResponse , 'ok' > ) {
125159 super ( response . statusText )
126160 Object . setPrototypeOf ( this , new . target . prototype )
127161
0 commit comments