Skip to content

Commit 2a81a07

Browse files
author
Mateusz Tkacz
committed
chore: improve result types
1 parent dffafc5 commit 2a81a07

File tree

2 files changed

+31
-11
lines changed

2 files changed

+31
-11
lines changed

packages/app/backend-http-client/src/client/sendByApiContract.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ describe('sendByApiContract', () => {
180180

181181
const response = await sendByApiContract(client, contract, {}, { requestLabel: 'test' })
182182

183+
expectTypeOf(response.error).toEqualTypeOf<UnexpectedResponseError | undefined>()
183184
expect(response.error).toBeDefined()
184185
expect(response.result).toBeUndefined()
185186
})
@@ -593,6 +594,9 @@ describe('sendByApiContract', () => {
593594
)
594595

595596
expect(callCount).toBe(1)
597+
expectTypeOf(result.error).toEqualTypeOf<
598+
UnexpectedResponseError | { statusCode: 429; headers: Record<string, string | undefined>; body: { message: string } } | undefined
599+
>()
596600
expect(result.error).toMatchObject({ statusCode: 429 })
597601
expect(result.result).toBeUndefined()
598602
})

packages/app/backend-http-client/src/client/sendByApiContract.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,31 @@ import type { RetryConfig } from 'undici-retry'
1717
import type { HttpRequestContext } from './types.ts'
1818
import { UnexpectedResponseError } from './UnexpectedResponseError.ts'
1919

20-
// captureAsError: true → filter to success codes only; captureAsError: false → all codes from contract
21-
type CaptureAsErrorFilter<T, TDoCaptureAsError extends boolean> = TDoCaptureAsError extends true
22-
? Extract<T, { statusCode: SuccessfulHttpStatusCode }>
23-
: T
20+
type AllContractResponses<
21+
TApiContract extends ApiContract,
22+
TIsStreaming extends boolean,
23+
> = TIsStreaming extends true
24+
? InferSseClientResponse<TApiContract>
25+
: InferNonSseClientResponse<TApiContract>
26+
27+
// captureAsError: true → success codes only; captureAsError: false → all codes from contract
28+
type ContractResultType<
29+
TApiContract extends ApiContract,
30+
TIsStreaming extends boolean,
31+
TDoCaptureAsError extends boolean,
32+
> = TDoCaptureAsError extends true
33+
? Extract<AllContractResponses<TApiContract, TIsStreaming>, { statusCode: SuccessfulHttpStatusCode }>
34+
: AllContractResponses<TApiContract, TIsStreaming>
35+
36+
// captureAsError: true → UnexpectedResponseError | <error-status-code responses from contract>
37+
// captureAsError: false → only UnexpectedResponseError (all contract responses go to result)
38+
type ContractErrorType<
39+
TApiContract extends ApiContract,
40+
TIsStreaming extends boolean,
41+
TDoCaptureAsError extends boolean,
42+
> = TDoCaptureAsError extends true
43+
? UnexpectedResponseError | Exclude<AllContractResponses<TApiContract, TIsStreaming>, { statusCode: SuccessfulHttpStatusCode }>
44+
: UnexpectedResponseError
2445

2546
export type ContractRequestOptions<DoCaptureAsError extends boolean = boolean> = {
2647
requestLabel: string
@@ -55,13 +76,8 @@ type ReturnTypeForContract<
5576
TIsStreaming extends boolean,
5677
TDoCaptureAsError extends boolean,
5778
> = Either<
58-
UnexpectedResponseError,
59-
CaptureAsErrorFilter<
60-
TIsStreaming extends true
61-
? InferSseClientResponse<TApiContract>
62-
: InferNonSseClientResponse<TApiContract>,
63-
TDoCaptureAsError
64-
>
79+
ContractErrorType<TApiContract, TIsStreaming, TDoCaptureAsError>,
80+
ContractResultType<TApiContract, TIsStreaming, TDoCaptureAsError>
6581
>
6682

6783
function toUndiciRetryOptions(config: RetryConfig): RetryHandler.RetryOptions {

0 commit comments

Comments
 (0)