@sapporta/rest-core 3.52.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +10 -0
- package/.eslintrc.json +21 -0
- package/CHANGELOG.md +3 -0
- package/LICENCE +21 -0
- package/README.md +19 -0
- package/jest.config.ts +16 -0
- package/package.json +33 -0
- package/project.json +51 -0
- package/src/index.ts +15 -0
- package/src/lib/client.spec.ts +1330 -0
- package/src/lib/client.ts +481 -0
- package/src/lib/dsl.spec.ts +1308 -0
- package/src/lib/dsl.ts +472 -0
- package/src/lib/fetch.spec.ts +102 -0
- package/src/lib/infer-types.spec.ts +935 -0
- package/src/lib/infer-types.ts +282 -0
- package/src/lib/paths.spec.ts +138 -0
- package/src/lib/paths.ts +61 -0
- package/src/lib/query.spec.ts +329 -0
- package/src/lib/query.ts +114 -0
- package/src/lib/response-error.spec.ts +67 -0
- package/src/lib/response-error.ts +61 -0
- package/src/lib/response-validation-error.ts +24 -0
- package/src/lib/server.spec.ts +163 -0
- package/src/lib/server.ts +83 -0
- package/src/lib/standard-schema-utils.spec.ts +218 -0
- package/src/lib/standard-schema-utils.ts +280 -0
- package/src/lib/standard-schema.ts +71 -0
- package/src/lib/status-codes.ts +75 -0
- package/src/lib/test-helpers.ts +7 -0
- package/src/lib/type-guards.spec.ts +355 -0
- package/src/lib/type-guards.ts +99 -0
- package/src/lib/type-utils.spec.ts +59 -0
- package/src/lib/type-utils.ts +234 -0
- package/src/lib/unknown-status-error.ts +15 -0
- package/src/lib/validation-error.ts +36 -0
- package/tsconfig.json +22 -0
- package/tsconfig.lib.json +10 -0
- package/tsconfig.spec.json +9 -0
- package/typedoc.json +5 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isResponse,
|
|
3
|
+
isSuccessResponse,
|
|
4
|
+
isErrorResponse,
|
|
5
|
+
isUnknownResponse,
|
|
6
|
+
isUnknownSuccessResponse,
|
|
7
|
+
isUnknownErrorResponse,
|
|
8
|
+
} from './type-guards';
|
|
9
|
+
import { initContract } from './dsl';
|
|
10
|
+
import { Equal, Expect } from './test-helpers';
|
|
11
|
+
import {
|
|
12
|
+
ErrorHttpStatusCode,
|
|
13
|
+
HTTPStatusCode,
|
|
14
|
+
SuccessfulHttpStatusCode,
|
|
15
|
+
} from './status-codes';
|
|
16
|
+
|
|
17
|
+
const c = initContract();
|
|
18
|
+
|
|
19
|
+
describe('Type Guards', () => {
|
|
20
|
+
const contract = c.router({
|
|
21
|
+
getPost: {
|
|
22
|
+
method: 'GET',
|
|
23
|
+
path: '/posts/:id',
|
|
24
|
+
responses: {
|
|
25
|
+
200: c.type<{ id: string }>(),
|
|
26
|
+
404: c.type<{ message: string }>(),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
getPostStrict: {
|
|
30
|
+
method: 'GET',
|
|
31
|
+
path: '/posts/:id',
|
|
32
|
+
responses: {
|
|
33
|
+
200: c.type<{ id: string }>(),
|
|
34
|
+
404: c.type<{ message: string }>(),
|
|
35
|
+
},
|
|
36
|
+
strictStatusCodes: true,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
type ResponseType = {
|
|
41
|
+
status: number;
|
|
42
|
+
body: unknown;
|
|
43
|
+
headers: Headers;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const errorObject = new Error('Error');
|
|
47
|
+
|
|
48
|
+
const successResponse: ResponseType = {
|
|
49
|
+
status: 200,
|
|
50
|
+
body: {
|
|
51
|
+
id: '1',
|
|
52
|
+
},
|
|
53
|
+
headers: new Headers(),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const errorResponse: ResponseType = {
|
|
57
|
+
status: 404,
|
|
58
|
+
body: {
|
|
59
|
+
message: 'Not Found',
|
|
60
|
+
},
|
|
61
|
+
headers: new Headers(),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const unknownSuccessResponse: ResponseType = {
|
|
65
|
+
status: 207,
|
|
66
|
+
body: 'Success',
|
|
67
|
+
headers: new Headers(),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const unknownErrorResponse: ResponseType = {
|
|
71
|
+
status: 500,
|
|
72
|
+
body: 'Server Error',
|
|
73
|
+
headers: new Headers(),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
describe('isResponse', () => {
|
|
77
|
+
it.each([
|
|
78
|
+
successResponse,
|
|
79
|
+
errorResponse,
|
|
80
|
+
unknownSuccessResponse,
|
|
81
|
+
unknownErrorResponse,
|
|
82
|
+
])('should return true for a valid response object', (response) => {
|
|
83
|
+
const result = isResponse(response, contract.getPost);
|
|
84
|
+
expect(result).toStrictEqual(true);
|
|
85
|
+
|
|
86
|
+
if (result) {
|
|
87
|
+
type TypeTest = Expect<
|
|
88
|
+
Equal<
|
|
89
|
+
typeof response,
|
|
90
|
+
| { status: 200; body: { id: string }; headers: Headers }
|
|
91
|
+
| { status: 404; body: { message: string }; headers: Headers }
|
|
92
|
+
| {
|
|
93
|
+
status: Exclude<HTTPStatusCode, 200 | 404>;
|
|
94
|
+
body: unknown;
|
|
95
|
+
headers: Headers;
|
|
96
|
+
}
|
|
97
|
+
>
|
|
98
|
+
>;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it.each([successResponse, errorResponse])(
|
|
103
|
+
'[strictStatusCode] should return true for a valid defined response object',
|
|
104
|
+
(response) => {
|
|
105
|
+
const result = isResponse(response, contract.getPostStrict);
|
|
106
|
+
expect(result).toStrictEqual(true);
|
|
107
|
+
|
|
108
|
+
if (result) {
|
|
109
|
+
type TypeTest = Expect<
|
|
110
|
+
Equal<
|
|
111
|
+
typeof response,
|
|
112
|
+
| { status: 200; body: { id: string }; headers: Headers }
|
|
113
|
+
| { status: 404; body: { message: string }; headers: Headers }
|
|
114
|
+
>
|
|
115
|
+
>;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
it.each([
|
|
121
|
+
errorObject,
|
|
122
|
+
null,
|
|
123
|
+
{},
|
|
124
|
+
{ status: 200, noBody: '' },
|
|
125
|
+
{ status: 200 },
|
|
126
|
+
])('should return false for an invalid response object', (response) => {
|
|
127
|
+
expect(isResponse(response)).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it.each([
|
|
131
|
+
unknownSuccessResponse,
|
|
132
|
+
unknownErrorResponse,
|
|
133
|
+
errorObject,
|
|
134
|
+
null,
|
|
135
|
+
{},
|
|
136
|
+
{ status: 200, noBody: '' },
|
|
137
|
+
{ status: 200 },
|
|
138
|
+
])(
|
|
139
|
+
'[strictStatusCode] should return false for an invalid response object or undefined response',
|
|
140
|
+
(response) => {
|
|
141
|
+
expect(isResponse(response, contract.getPostStrict)).toBe(false);
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('isSuccessResponse', () => {
|
|
147
|
+
it.each([successResponse, unknownSuccessResponse])(
|
|
148
|
+
'should return true for a successful response',
|
|
149
|
+
(response) => {
|
|
150
|
+
const result = isSuccessResponse(response, contract.getPost);
|
|
151
|
+
expect(result).toStrictEqual(true);
|
|
152
|
+
|
|
153
|
+
if (result) {
|
|
154
|
+
type TypeTest = Expect<
|
|
155
|
+
Equal<
|
|
156
|
+
typeof response,
|
|
157
|
+
| { status: 200; body: { id: string }; headers: Headers }
|
|
158
|
+
| {
|
|
159
|
+
status: Exclude<SuccessfulHttpStatusCode, 200>;
|
|
160
|
+
body: unknown;
|
|
161
|
+
headers: Headers;
|
|
162
|
+
}
|
|
163
|
+
>
|
|
164
|
+
>;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
it.each([successResponse])(
|
|
170
|
+
'[strictStatusCode] should return true for a successful response',
|
|
171
|
+
(response) => {
|
|
172
|
+
const result = isSuccessResponse(response, contract.getPostStrict);
|
|
173
|
+
expect(result).toStrictEqual(true);
|
|
174
|
+
|
|
175
|
+
if (result) {
|
|
176
|
+
type TypeTest = Expect<
|
|
177
|
+
Equal<
|
|
178
|
+
typeof response,
|
|
179
|
+
{ status: 200; body: { id: string }; headers: Headers }
|
|
180
|
+
>
|
|
181
|
+
>;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
it.each([errorResponse, unknownErrorResponse])(
|
|
187
|
+
'should return false for a non-successful response',
|
|
188
|
+
(response) => {
|
|
189
|
+
expect(isSuccessResponse(response)).toStrictEqual(false);
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
it.each([unknownSuccessResponse, errorResponse, unknownErrorResponse])(
|
|
194
|
+
'should return false for a non-successful response',
|
|
195
|
+
(response) => {
|
|
196
|
+
expect(
|
|
197
|
+
isSuccessResponse(response, contract.getPostStrict),
|
|
198
|
+
).toStrictEqual(false);
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('isErrorResponse', () => {
|
|
204
|
+
it.each([errorResponse, unknownErrorResponse])(
|
|
205
|
+
'should return true for an error response',
|
|
206
|
+
(response) => {
|
|
207
|
+
const result = isErrorResponse(response, contract.getPost);
|
|
208
|
+
expect(result).toStrictEqual(true);
|
|
209
|
+
|
|
210
|
+
if (result) {
|
|
211
|
+
type TypeTest = Expect<
|
|
212
|
+
Equal<
|
|
213
|
+
typeof response,
|
|
214
|
+
| { status: 404; body: { message: string }; headers: Headers }
|
|
215
|
+
| {
|
|
216
|
+
status: Exclude<ErrorHttpStatusCode, 404>;
|
|
217
|
+
body: unknown;
|
|
218
|
+
headers: Headers;
|
|
219
|
+
}
|
|
220
|
+
>
|
|
221
|
+
>;
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
it.each([errorResponse])(
|
|
227
|
+
'[strictStatusCode] should return true for an error response',
|
|
228
|
+
(response) => {
|
|
229
|
+
const result = isErrorResponse(response, contract.getPostStrict);
|
|
230
|
+
expect(result).toStrictEqual(true);
|
|
231
|
+
|
|
232
|
+
if (result) {
|
|
233
|
+
type TypeTest = Expect<
|
|
234
|
+
Equal<
|
|
235
|
+
typeof response,
|
|
236
|
+
{ status: 404; body: { message: string }; headers: Headers }
|
|
237
|
+
>
|
|
238
|
+
>;
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
it.each([successResponse, unknownSuccessResponse])(
|
|
244
|
+
'should return false for a non-error response',
|
|
245
|
+
(response) => {
|
|
246
|
+
expect(isErrorResponse(response)).toStrictEqual(false);
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
it.each([unknownErrorResponse, successResponse, unknownSuccessResponse])(
|
|
251
|
+
'should return false for a non-error response',
|
|
252
|
+
(response) => {
|
|
253
|
+
expect(isErrorResponse(response, contract.getPostStrict)).toStrictEqual(
|
|
254
|
+
false,
|
|
255
|
+
);
|
|
256
|
+
},
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe('isUnknownResponse', () => {
|
|
261
|
+
it.each([unknownSuccessResponse, unknownErrorResponse])(
|
|
262
|
+
'should return true for responses not defined in the contract',
|
|
263
|
+
(response) => {
|
|
264
|
+
const result = isUnknownResponse(response, contract.getPost);
|
|
265
|
+
expect(result).toStrictEqual(true);
|
|
266
|
+
|
|
267
|
+
if (result) {
|
|
268
|
+
type TypeTest = Expect<
|
|
269
|
+
Equal<
|
|
270
|
+
typeof response,
|
|
271
|
+
{
|
|
272
|
+
status: Exclude<HTTPStatusCode, 200 | 404>;
|
|
273
|
+
body: unknown;
|
|
274
|
+
headers: Headers;
|
|
275
|
+
}
|
|
276
|
+
>
|
|
277
|
+
>;
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
it.each([successResponse, errorResponse])(
|
|
283
|
+
'should return false for a response defined in the contract',
|
|
284
|
+
(response) => {
|
|
285
|
+
expect(isUnknownResponse(response, contract.getPost)).toStrictEqual(
|
|
286
|
+
false,
|
|
287
|
+
);
|
|
288
|
+
},
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe('isUnknownSuccessResponse', () => {
|
|
293
|
+
it.each([unknownSuccessResponse])(
|
|
294
|
+
'should return true for successful responses not defined in the contract or error responses',
|
|
295
|
+
(response) => {
|
|
296
|
+
const result = isUnknownSuccessResponse(response, contract.getPost);
|
|
297
|
+
expect(result).toStrictEqual(true);
|
|
298
|
+
|
|
299
|
+
if (result) {
|
|
300
|
+
type TypeTest = Expect<
|
|
301
|
+
Equal<
|
|
302
|
+
typeof response,
|
|
303
|
+
{
|
|
304
|
+
status: Exclude<SuccessfulHttpStatusCode, 200>;
|
|
305
|
+
body: unknown;
|
|
306
|
+
headers: Headers;
|
|
307
|
+
}
|
|
308
|
+
>
|
|
309
|
+
>;
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
it.each([successResponse, errorResponse, unknownErrorResponse])(
|
|
315
|
+
'should return false for a success response defined in the contract or non-success responses',
|
|
316
|
+
(response) => {
|
|
317
|
+
expect(
|
|
318
|
+
isUnknownSuccessResponse(response, contract.getPost),
|
|
319
|
+
).toStrictEqual(false);
|
|
320
|
+
},
|
|
321
|
+
);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
describe('isUnknownErrorResponse', () => {
|
|
325
|
+
it.each([unknownErrorResponse])(
|
|
326
|
+
'should return true for error responses not defined in the contract or successful responses',
|
|
327
|
+
(response) => {
|
|
328
|
+
const result = isUnknownErrorResponse(response, contract.getPost);
|
|
329
|
+
expect(result).toStrictEqual(true);
|
|
330
|
+
|
|
331
|
+
if (result) {
|
|
332
|
+
type TypeTest = Expect<
|
|
333
|
+
Equal<
|
|
334
|
+
typeof response,
|
|
335
|
+
{
|
|
336
|
+
status: Exclude<ErrorHttpStatusCode, 404>;
|
|
337
|
+
body: unknown;
|
|
338
|
+
headers: Headers;
|
|
339
|
+
}
|
|
340
|
+
>
|
|
341
|
+
>;
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
it.each([errorResponse, successResponse, unknownSuccessResponse])(
|
|
347
|
+
'should return false for an error response defined in the contract or non-error responses',
|
|
348
|
+
(response) => {
|
|
349
|
+
expect(
|
|
350
|
+
isUnknownErrorResponse(response, contract.getPost),
|
|
351
|
+
).toStrictEqual(false);
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
});
|
|
355
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { AppRoute } from './dsl';
|
|
2
|
+
import {
|
|
3
|
+
ClientInferResponses,
|
|
4
|
+
InferResponseUndefinedStatusCodes,
|
|
5
|
+
} from './infer-types';
|
|
6
|
+
import {
|
|
7
|
+
ErrorHttpStatusCode,
|
|
8
|
+
HTTPStatusCode,
|
|
9
|
+
SuccessfulHttpStatusCode,
|
|
10
|
+
} from './status-codes';
|
|
11
|
+
|
|
12
|
+
export const isResponse = <T extends AppRoute>(
|
|
13
|
+
response: unknown,
|
|
14
|
+
contractEndpoint?: T,
|
|
15
|
+
): response is ClientInferResponses<T, HTTPStatusCode> => {
|
|
16
|
+
return (
|
|
17
|
+
typeof response === 'object' &&
|
|
18
|
+
response !== null &&
|
|
19
|
+
'status' in response &&
|
|
20
|
+
'body' in response &&
|
|
21
|
+
typeof response.status === 'number' &&
|
|
22
|
+
response.status >= 200 &&
|
|
23
|
+
response.status < 600 &&
|
|
24
|
+
(contractEndpoint?.strictStatusCodes
|
|
25
|
+
? Object.keys(contractEndpoint.responses).includes(
|
|
26
|
+
response.status.toString(),
|
|
27
|
+
)
|
|
28
|
+
: true)
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const isSuccessResponse = <T extends AppRoute>(
|
|
33
|
+
response: unknown,
|
|
34
|
+
contractEndpoint?: T,
|
|
35
|
+
): response is ClientInferResponses<T, SuccessfulHttpStatusCode> => {
|
|
36
|
+
return (
|
|
37
|
+
isResponse(response, contractEndpoint) &&
|
|
38
|
+
response.status >= 200 &&
|
|
39
|
+
response.status < 300
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const isErrorResponse = <T extends AppRoute>(
|
|
44
|
+
response: unknown,
|
|
45
|
+
contractEndpoint?: T,
|
|
46
|
+
): response is ClientInferResponses<T, ErrorHttpStatusCode> => {
|
|
47
|
+
return (
|
|
48
|
+
isResponse(response, contractEndpoint) &&
|
|
49
|
+
!isSuccessResponse(response, contractEndpoint)
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const isUnknownResponse = <T extends AppRoute>(
|
|
54
|
+
response: unknown,
|
|
55
|
+
contractEndpoint: T,
|
|
56
|
+
): response is ClientInferResponses<
|
|
57
|
+
T,
|
|
58
|
+
InferResponseUndefinedStatusCodes<T>,
|
|
59
|
+
'ignore'
|
|
60
|
+
> => {
|
|
61
|
+
return (
|
|
62
|
+
isResponse(response) &&
|
|
63
|
+
!Object.keys(contractEndpoint.responses).includes(
|
|
64
|
+
response.status.toString(),
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const isUnknownSuccessResponse = <T extends AppRoute>(
|
|
70
|
+
response: unknown,
|
|
71
|
+
contractEndpoint: T,
|
|
72
|
+
): response is ClientInferResponses<
|
|
73
|
+
T,
|
|
74
|
+
InferResponseUndefinedStatusCodes<T, SuccessfulHttpStatusCode>,
|
|
75
|
+
'ignore'
|
|
76
|
+
> => {
|
|
77
|
+
return (
|
|
78
|
+
isSuccessResponse(response) && isUnknownResponse(response, contractEndpoint)
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const isUnknownErrorResponse = <T extends AppRoute>(
|
|
83
|
+
response: unknown,
|
|
84
|
+
contractEndpoint: T,
|
|
85
|
+
): response is ClientInferResponses<
|
|
86
|
+
T,
|
|
87
|
+
InferResponseUndefinedStatusCodes<T, ErrorHttpStatusCode>,
|
|
88
|
+
'ignore'
|
|
89
|
+
> => {
|
|
90
|
+
return (
|
|
91
|
+
isErrorResponse(response) && isUnknownResponse(response, contractEndpoint)
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const exhaustiveGuard = <T extends { status: never }>(
|
|
96
|
+
response: T,
|
|
97
|
+
): never => {
|
|
98
|
+
throw new Error(`Unreachable code: Response status is ${response.status}`);
|
|
99
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { Equal, Expect } from './test-helpers';
|
|
4
|
+
import {
|
|
5
|
+
AreAllPropertiesOptional,
|
|
6
|
+
Without,
|
|
7
|
+
SchemaOutputOrType,
|
|
8
|
+
} from './type-utils';
|
|
9
|
+
|
|
10
|
+
const zodObject = z.object({ title: z.string() });
|
|
11
|
+
type Test1 = SchemaOutputOrType<typeof zodObject>;
|
|
12
|
+
|
|
13
|
+
const zodObjectNullable = zodObject.nullable();
|
|
14
|
+
type Test2 = SchemaOutputOrType<typeof zodObject>;
|
|
15
|
+
|
|
16
|
+
type Test3 = SchemaOutputOrType<{ title: string }>;
|
|
17
|
+
|
|
18
|
+
it.todo('should infer type');
|
|
19
|
+
|
|
20
|
+
type AreAllPropertiesOptional1 = Expect<
|
|
21
|
+
Equal<AreAllPropertiesOptional<{ a: string; b?: string }>, false>
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
type AreAllPropertiesOptional2 = Expect<
|
|
25
|
+
Equal<AreAllPropertiesOptional<{ a?: string; b?: string }>, true>
|
|
26
|
+
>;
|
|
27
|
+
|
|
28
|
+
type AreAllPropertiesOptional3 = Expect<
|
|
29
|
+
Equal<
|
|
30
|
+
AreAllPropertiesOptional<{
|
|
31
|
+
params: {
|
|
32
|
+
id: string;
|
|
33
|
+
};
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
}>,
|
|
36
|
+
false
|
|
37
|
+
>
|
|
38
|
+
>;
|
|
39
|
+
|
|
40
|
+
type WithoutTest = Expect<
|
|
41
|
+
Equal<
|
|
42
|
+
Without<
|
|
43
|
+
{
|
|
44
|
+
body: never;
|
|
45
|
+
params: {
|
|
46
|
+
id: string;
|
|
47
|
+
};
|
|
48
|
+
headers?: Record<string, string>;
|
|
49
|
+
},
|
|
50
|
+
never
|
|
51
|
+
>,
|
|
52
|
+
{
|
|
53
|
+
params: {
|
|
54
|
+
id: string;
|
|
55
|
+
};
|
|
56
|
+
headers?: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
>
|
|
59
|
+
>;
|