Skip to content

Commit 31e5f8f

Browse files
fix(client): correct return types when throw option is true (#127)
When throw: true is set in client options, the response type should be the data directly, not { data, error } wrapper. This fix uses the third generic parameter of BetterFetchResponse to properly infer the return type based on the throw option.
1 parent 379bf31 commit 31e5f8f

2 files changed

Lines changed: 42 additions & 7 deletions

File tree

packages/better-call/src/client.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,4 +332,29 @@ describe("client", () => {
332332
});
333333
client("/test2", { body: undefined, query: undefined, params: undefined });
334334
});
335+
336+
it("should return unwrapped type T when throw: true is set", async () => {
337+
const itemEndpoint = createEndpoint(
338+
"/item",
339+
{ method: "GET" },
340+
async () => ({ id: "123", name: "test" }),
341+
);
342+
343+
const router = createRouter({ itemEndpoint });
344+
345+
const client = createClient<typeof router>({
346+
baseURL: "http://localhost:3000",
347+
customFetchImpl: async (url, init) => {
348+
return router.handler(new Request(url, init));
349+
},
350+
});
351+
352+
const res = await client("/item", {
353+
throw: true,
354+
});
355+
356+
expect(res).toMatchObject({ id: "123", name: "test" });
357+
358+
expectTypeOf(res).toExtend<{ id: string; name: string }>();
359+
});
335360
});

packages/better-call/src/client.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,11 @@ export type RequiredOptionKeys<
9797
params: true;
9898
});
9999

100-
export const createClient = <R extends Router | Router["endpoints"]>(
101-
options?: ClientOptions,
100+
export const createClient = <
101+
R extends Router | Router["endpoints"],
102+
GlobalOpts extends ClientOptions = ClientOptions,
103+
>(
104+
options?: GlobalOpts,
102105
) => {
103106
const fetch = createFetch(options ?? {});
104107
type API = InferClientRoutes<
@@ -121,25 +124,32 @@ export const createClient = <R extends Router | Router["endpoints"]>(
121124
OPT extends O,
122125
K extends keyof OPT,
123126
C extends InferContext<OPT[K]>,
127+
CallOpts extends BetterFetchOption<C["body"], C["query"], C["params"]>,
124128
>(
125129
path: K,
126-
...options: HasRequired<C> extends true
130+
...callOptions: HasRequired<C> extends true
127131
? [
128132
WithRequired<
129133
BetterFetchOption<C["body"], C["query"], C["params"]>,
130134
keyof RequiredOptionKeys<C>
131135
>,
132136
]
133-
: [BetterFetchOption<C["body"], C["query"], C["params"]>?]
137+
: [CallOpts?]
134138
): Promise<
135139
BetterFetchResponse<
136-
Awaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>
140+
Awaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>,
141+
unknown,
142+
CallOpts["throw"] extends boolean
143+
? CallOpts["throw"]
144+
: GlobalOpts["throw"] extends true
145+
? true
146+
: false
137147
>
138148
> => {
139149
return (await fetch(path as string, {
140-
...options[0],
150+
...callOptions[0],
141151
})) as any;
142152
};
143153
};
144154

145-
export * from "./error";
155+
export * from "./error";

0 commit comments

Comments
 (0)