Skip to content

Commit f67a961

Browse files
committed
Allow to omit init arg of fetch
1 parent f6deb86 commit f67a961

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

pkgs/typed-api-spec/src/fetch/index.t-test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,22 @@ type ValidateUrlTestCase = [
4545
};
4646
};
4747
};
48+
"/users2": {
49+
get: {
50+
headers: { "x-foo"?: string; "x-bar"?: string };
51+
responses: { 200: { body: { prop: string } } };
52+
};
53+
};
4854
}>;
4955
(async () => {
5056
const f = fetch as FetchT<"", Spec>;
5157
{
52-
// @ts-expect-error 今はinitの省略ができないが、できるようにしたい
58+
// get methodが定義されており、headersが必要ない場合、Initは省略可能
5359
await f("/users");
5460

61+
// headersが定義されていても、すべて省略可能な場合はInitも省略可能
62+
await f("/users2");
63+
5564
// methodを省略した場合はgetとして扱う
5665
const res = await f("/users", {});
5766
(await res.json()).prop;
@@ -63,6 +72,31 @@ type ValidateUrlTestCase = [
6372
}
6473
})();
6574
}
75+
{
76+
type Spec = DefineApiEndpoints<{
77+
"/users": {
78+
get: {
79+
headers: { "x-foo"?: string; "Content-Type": "application/json" };
80+
responses: { 200: { body: { prop: string } } };
81+
};
82+
};
83+
"/users2": {
84+
post: {
85+
responses: { 200: { body: { prop: string } } };
86+
};
87+
};
88+
}>;
89+
(async () => {
90+
const f = fetch as FetchT<"", Spec>;
91+
{
92+
// @ts-expect-error getメソッドが定義されていても、headersが要求されている場合はInitは省略できない
93+
await f("/users");
94+
95+
// @ts-expect-error getメソッドが定義されていない場合、Initは省略できない
96+
await f("/users2");
97+
}
98+
})();
99+
}
66100
{
67101
type Spec = DefineApiEndpoints<{
68102
"/users": {

pkgs/typed-api-spec/src/fetch/index.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ type FetchT<UrlPrefix extends UrlPrefixPattern, E extends ApiEndpoints> = <
141141
: never,
142142
LM extends Lowercase<InputMethod>,
143143
Query extends ApiP<E, CandidatePaths, LM, "query">,
144+
Headers extends ApiP<E, CandidatePaths, LM, "headers">,
145+
Body extends ApiP<E, CandidatePaths, LM, "body">,
144146
Response extends ApiP<
145147
E,
146148
CandidatePaths,
@@ -154,17 +156,25 @@ type FetchT<UrlPrefix extends UrlPrefixPattern, E extends ApiEndpoints> = <
154156
AcceptableMethods,
155157
"get"
156158
>,
159+
CanOmitMethod extends boolean = "get" extends AcceptableMethods
160+
? true
161+
: false,
162+
CanOmitInit extends boolean = CanOmitMethod extends true
163+
? Headers extends undefined
164+
? true
165+
: Headers extends Record<string, string>
166+
? IsAllOptional<Headers> extends true
167+
? true
168+
: false
169+
: false
170+
: false,
157171
>(
158172
input: [ValidatedUrl] extends [C.OK | QueryParameterRequiredError]
159173
? Input
160174
: ValidatedUrl,
161-
init: RequestInitT<
162-
// If `get` method is defined in the spec, method can be omitted
163-
"get" extends AcceptableMethods ? true : false,
164-
ApiP<E, CandidatePaths, LM, "body">,
165-
ApiP<E, CandidatePaths, LM, "headers">,
166-
InputMethod
167-
>,
175+
...args: CanOmitInit extends true
176+
? [init?: RequestInitT<CanOmitMethod, Body, Headers, InputMethod>]
177+
: [init: RequestInitT<CanOmitMethod, Body, Headers, InputMethod>]
168178
) => Promise<Response>;
169179

170180
export default FetchT;

0 commit comments

Comments
 (0)