Skip to content

Commit

Permalink
feat(client): add DefaultResponse config support
Browse files Browse the repository at this point in the history
  • Loading branch information
NamesMT committed Aug 18, 2024
1 parent 3670716 commit 9248417
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 19 deletions.
24 changes: 21 additions & 3 deletions src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,26 @@ class ClientRequestImpl {
}
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const hc = <T extends Hono<any, any, any>>(

/**
* @param baseUrl The base URL of the Hono instance.
* @param options The options for the client.
* @returns A hono API client instance.
*
* **Typedoc**: <Hono, DefaultResponse>
*
* - Hono: The type of the Hono instance.
*
* - DefaultResponse: This is used in cases where the response is unknown,
* e.g. checking for an unknown status code:
* ```ts
* // The response of status code 400 is processed by a middleware and not explicitly defined in the router type flow.
* if (res.status === 400) {
* const data = await res.json() // will be typeof `DefaultResponse`
* }
* ```
*/
export const hc = <H extends Hono<any, any, any>, DefaultResponse = {}>(
baseUrl: string,
options?: ClientRequestOptions
) =>
Expand Down Expand Up @@ -211,4 +229,4 @@ export const hc = <T extends Hono<any, any, any>>(
return req.fetch(opts.args[0], args)
}
return req
}, []) as UnionToIntersection<Client<T>>
}, []) as UnionToIntersection<Client<H, DefaultResponse>>
40 changes: 24 additions & 16 deletions src/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ export type ClientRequestOptions<T = unknown> = {
headers: T | (() => T | Promise<T>)
})

export type ClientRequest<S extends Schema> = {
export type ClientRequest<S extends Schema, DefaultResponse = {}> = {
[M in keyof S]: S[M] extends Endpoint & { input: infer R }
? R extends object
? HasRequiredKeys<R> extends true
? (args: R, options?: ClientRequestOptions) => Promise<ClientResponseOfEndpoint<S[M]>>
: (args?: R, options?: ClientRequestOptions) => Promise<ClientResponseOfEndpoint<S[M]>>
? (args: R, options?: ClientRequestOptions) => Promise<ClientResponseOfEndpoint<S[M], DefaultResponse>>
: (args?: R, options?: ClientRequestOptions) => Promise<ClientResponseOfEndpoint<S[M], DefaultResponse>>
: never
: never
} & {
Expand Down Expand Up @@ -58,20 +58,20 @@ type BlankRecordToNever<T> = T extends any
: T
: never

type ClientResponseOfEndpoint<T extends Endpoint = Endpoint> = T extends {
type ClientResponseOfEndpoint<T extends Endpoint = Endpoint, DefaultResponse = {}> = T extends {
output: infer O
outputFormat: infer F
status: infer S
}
? F extends 'redirect'
? ClientResponse<O, S extends RedirectStatusCode ? S : never, 'redirect'>
:
| ClientResponse<O, S extends StatusCode ? S : never, F extends ResponseFormat ? F : never>
| ClientResponse<
{},
S extends StatusCode ? Exclude<Exclude<StatusCode, RedirectStatusCode>, S> : never,
F extends ResponseFormat ? F : never
>
| ClientResponse<O, S extends StatusCode ? S : never, F extends ResponseFormat ? F : never>
| ClientResponse<
DefaultResponse,
S extends StatusCode ? Exclude<Exclude<StatusCode, RedirectStatusCode>, S> : never,
F extends ResponseFormat ? F : never
>
: never

export interface ClientResponse<
Expand Down Expand Up @@ -156,25 +156,33 @@ export type InferRequestOptionsType<T> = T extends (
? NonNullable<R>
: never

type PathChaining<
Path extends string,
E extends Schema,
DefaultResponse = {}
> = PathToChain<Path, E, Path, DefaultResponse>

type PathToChain<
Path extends string,
E extends Schema,
Original extends string = Path
Original extends string = Path,
DefaultResponse = {}
> = Path extends `/${infer P}`
? PathToChain<P, E, Path>
? PathToChain<P, E, Path, DefaultResponse>
: Path extends `${infer P}/${infer R}`
? { [K in P]: PathToChain<R, E, Original> }
? { [K in P]: PathToChain<R, E, Original, DefaultResponse> }
: {
[K in Path extends '' ? 'index' : Path]: ClientRequest<
E extends Record<string, unknown> ? E[Original] : never
E extends Record<string, unknown> ? E[Original] : never,
DefaultResponse
>
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Client<T> = T extends Hono<any, infer S, any>
export type Client<T, DefaultResponse = {}> = T extends Hono<any, infer S, any>
? S extends Record<infer K, Schema>
? K extends string
? PathToChain<K, S>
? PathChaining<K, S, DefaultResponse>
: never
: never
: never
Expand Down

0 comments on commit 9248417

Please sign in to comment.