Skip to content

Commit b3cf4c1

Browse files
authored
Merge pull request #218 from atomic-state/features/params-types
features(params):
2 parents c85d7bd + a9fdcb3 commit b3cf4c1

6 files changed

Lines changed: 138 additions & 58 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "http-react",
3-
"version": "3.8.7",
3+
"version": "3.8.8",
44
"description": "React hooks for data fetching",
55
"main": "dist/index.js",
66
"scripts": {

src/hooks/others.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ export function useServerAction<T extends (args: any) => any>(
699699
let mockServerActionId = config?.id ?? getMockServerActionId(action)
700700

701701
const $action = useFetch(mockServerActionId, {
702+
params: {},
702703
fetcher: async function proxied(_, config) {
703704
const actionParam = actionForms.get(mockServerActionId) ?? config?.params
704705
$action.resetError()

src/hooks/use-fetch.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import {
4141
FetchContextType,
4242
HTTP_METHODS,
4343
ImperativeFetch,
44+
StaticFetchConfig,
45+
StaticFetchConfigNoUrl,
4446
TimeSpan
4547
} from '../types'
4648

@@ -82,9 +84,16 @@ const temporaryFormData = new Map()
8284
/**
8385
* Fetch hook
8486
*/
85-
export function useFetch<FetchDataType = any, TransformData = any>(
86-
init: FetchConfigType<FetchDataType, TransformData> | string | Request,
87-
options?: FetchConfigTypeNoUrl<FetchDataType, TransformData>
87+
export function useFetch<
88+
FetchDataType = any,
89+
TransformData = any,
90+
UrlType extends string = string
91+
>(
92+
init:
93+
| StaticFetchConfig<FetchDataType, TransformData, UrlType>
94+
| UrlType
95+
| Request,
96+
options?: StaticFetchConfigNoUrl<FetchDataType, TransformData, UrlType>
8897
) {
8998
const $ctx = useHRFContext()
9099

@@ -129,7 +138,7 @@ export function useFetch<FetchDataType = any, TransformData = any>(
129138
...options,
130139
// @ts-expect-error
131140
id: init?.id ?? init?.key
132-
} as Required<FetchConfigType<FetchDataType, TransformData>>)
141+
} as Required<StaticFetchConfig<FetchDataType, TransformData, UrlType>>)
133142

134143
const {
135144
onOnline = ctx.onOnline,

src/types/index.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,3 +371,53 @@ export type FetchInit<FDT = any, TransformData = any> = FetchConfigType<
371371
FDT,
372372
TransformData
373373
>;
374+
375+
// types related to params parsing
376+
377+
/** Helper type to extract the parameter name from a segment like :id or {id} or [id] */
378+
export type ExtractParam<Segment extends string> =
379+
Segment extends `[${infer Name}]`
380+
? Name // [name]
381+
: Segment extends `:${infer Name}`
382+
? Name // :name
383+
: Segment extends `{${infer Name}}`
384+
? Name // {name}
385+
: never;
386+
387+
type CleanPath<Path extends string> = Path extends `/${infer Rest}`
388+
? CleanPath<Rest>
389+
: Path extends `${infer Rest}/`
390+
? CleanPath<Rest>
391+
: Path extends `${infer Base}?${any}`
392+
? CleanPath<Base>
393+
: Path;
394+
395+
type ParsePathParams<Path extends string> =
396+
Path extends `${infer Segment}/${infer Rest}`
397+
? (ExtractParam<Segment> extends never
398+
? {}
399+
: { [K in ExtractParam<Segment>]: string | number }) &
400+
ParsePathParams<Rest>
401+
: ExtractParam<Path> extends never
402+
? {}
403+
: { [K in ExtractParam<Path>]: string | number };
404+
405+
export type PathParams<Path extends string> = ParsePathParams<CleanPath<Path>>;
406+
407+
export type StaticParams<UrlType extends string> =
408+
PathParams<UrlType> extends Record<string, never>
409+
? { params?: any }
410+
: { params: PathParams<UrlType> };
411+
412+
export type StaticFetchConfig<D, T, U extends string> = Omit<
413+
FetchConfigType<D, T>,
414+
"url" | "params"
415+
> & {
416+
url?: U;
417+
} & StaticParams<U>;
418+
419+
export type StaticFetchConfigNoUrl<D, T, U extends string> = Omit<
420+
FetchConfigTypeNoUrl<D, T>,
421+
"params"
422+
> &
423+
StaticParams<U>;

src/utils/index.ts

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
requestInitialTimes,
1212
requestsProvider,
1313
runningMutate,
14-
valuesMemory,
14+
valuesMemory
1515
} from "../internal";
1616

1717
import { UNITS_MILISECONDS_EQUIVALENTS } from "../internal/constants";
@@ -24,6 +24,8 @@ import {
2424
TimeSpan,
2525
FetchConfigTypeNoUrl,
2626
FetchConfigType,
27+
StaticFetchConfig,
28+
StaticFetchConfigNoUrl
2729
} from "../types";
2830
import {
2931
gql,
@@ -32,7 +34,7 @@ import {
3234
isFunction,
3335
queue,
3436
serialize,
35-
windowExists,
37+
windowExists
3638
} from "./shared";
3739

3840
export function getMiliseconds(v: TimeSpan): number {
@@ -67,28 +69,28 @@ export const createImperativeFetch = (ctx: FetchContextType) => {
6769
"PATCH",
6870
"PURGE",
6971
"LINK",
70-
"UNLINK",
72+
"UNLINK"
7173
];
7274

7375
const { baseUrl } = ctx;
7476

7577
return {
7678
...Object.fromEntries(
7779
new Map(
78-
keys.map((k) => [
80+
keys.map(k => [
7981
k.toLowerCase(),
8082
(url, config = {}) =>
8183
(useFetch as any)[k.toLowerCase()](
8284
hasBaseUrl(url) ? url : baseUrl + url,
8385
{
8486
...ctx,
85-
...config,
87+
...config
8688
}
87-
),
89+
)
8890
])
8991
)
9092
),
91-
config: ctx,
93+
config: ctx
9294
} as ImperativeFetch;
9395
};
9496

@@ -101,7 +103,7 @@ export const useIsomorphicLayoutEffect = windowExists
101103
*/
102104
export function revalidate(id: any | any[], __reval__ = true) {
103105
if (Array.isArray(id)) {
104-
id.map((reqId) => {
106+
id.map(reqId => {
105107
if (isDefined(reqId)) {
106108
const key = serialize(reqId);
107109

@@ -118,7 +120,7 @@ export function revalidate(id: any | any[], __reval__ = true) {
118120
queue(() => {
119121
requestsProvider.emit(key, {
120122
loading: true,
121-
error: false,
123+
error: false
122124
});
123125
});
124126
}
@@ -142,7 +144,7 @@ export function revalidate(id: any | any[], __reval__ = true) {
142144
queue(() => {
143145
requestsProvider.emit(key, {
144146
loading: true,
145-
error: false,
147+
error: false
146148
});
147149
});
148150
}
@@ -157,17 +159,17 @@ export function revalidateKey(key: any) {
157159

158160
export function cancelRequest(id: any | any[]) {
159161
if (Array.isArray(id)) {
160-
id.map((reqId) => {
162+
id.map(reqId => {
161163
if (isDefined(reqId)) {
162164
const key = serialize({
163-
idString: serialize(reqId),
165+
idString: serialize(reqId)
164166
});
165167
if (isPending(key)) {
166168
revalidate(reqId, false);
167169
queue(() => {
168170
requestsProvider.emit(key, {
169171
loading: false,
170-
error: false,
172+
error: false
171173
});
172174
});
173175
}
@@ -176,14 +178,14 @@ export function cancelRequest(id: any | any[]) {
176178
} else {
177179
if (isDefined(id)) {
178180
const key = serialize({
179-
idString: serialize(id),
181+
idString: serialize(id)
180182
});
181183
if (isPending(key)) {
182184
revalidate(id, false);
183185
queue(() => {
184186
requestsProvider.emit(key, {
185187
loading: false,
186-
error: false,
188+
error: false
187189
});
188190
});
189191
}
@@ -249,7 +251,7 @@ export function queryProvider<R>(
249251

250252
const queryVariables = {
251253
...thisDefaults?.variables,
252-
...(otherConfig as any)?.variables,
254+
...(otherConfig as any)?.variables
253255
};
254256

255257
const { config = {} } = providerConfig || {};
@@ -276,7 +278,7 @@ export function queryProvider<R>(
276278
headers: {
277279
...others?.headers,
278280
...thisDefaults?.headers,
279-
...otherConfig?.headers,
281+
...otherConfig?.headers
280282
},
281283
...{ __fromProvider: true },
282284
default: {
@@ -287,15 +289,15 @@ export function queryProvider<R>(
287289
* 'value' property (when using the `gql` function)
288290
*/
289291
// @ts-ignore
290-
otherConfig?.default) as R[P]["value"],
292+
otherConfig?.default) as R[P]["value"]
291293
},
292-
variables: queryVariables,
294+
variables: queryVariables
293295
});
294296

295297
const thisData = useMemo(
296298
() => ({
297299
...g?.data,
298-
variables: queryVariables,
300+
variables: queryVariables
299301
}),
300302
[serialize({ data: g?.data, queryVariables })]
301303
);
@@ -304,9 +306,9 @@ export function queryProvider<R>(
304306
...g,
305307
config: {
306308
...g?.config,
307-
config: undefined,
309+
config: undefined
308310
},
309-
data: thisData,
311+
data: thisData
310312
} as Omit<typeof g, "data"> & {
311313
data: {
312314
data: QuerysType[P] extends ReturnType<typeof gql>
@@ -338,7 +340,7 @@ export function mutateData(
338340
requestsProvider.emit(key, {
339341
data: newVal,
340342
isMutating: true,
341-
requestCallId,
343+
requestCallId
342344
});
343345
if (_revalidate) {
344346
previousConfig.set(key, undefined);
@@ -353,7 +355,7 @@ export function mutateData(
353355
requestsProvider.emit(key, {
354356
requestCallId,
355357
isMutating: true,
356-
data: v,
358+
data: v
357359
});
358360
if (_revalidate) {
359361
previousConfig.set(key, undefined);
@@ -368,11 +370,16 @@ export function mutateData(
368370
}
369371
}
370372

371-
export function fetchOptions<T = any, TransformData = any>(
372-
init: string | FetchConfigType<T, TransformData>,
373-
options?: FetchConfigTypeNoUrl<T, TransformData>
374-
) {
373+
export function fetchOptions<
374+
T = any,
375+
TransformData = any,
376+
UrlType extends string = string
377+
>(
378+
init: UrlType | StaticFetchConfig<T, TransformData, UrlType>,
379+
options?: Partial<StaticFetchConfigNoUrl<T, TransformData, UrlType>>
380+
): StaticFetchConfig<T, TransformData, UrlType> {
381+
// Changed return type
375382
return (
376383
typeof init === "string" ? { url: init, ...options } : init
377-
) as FetchConfigType<T, TransformData>;
384+
) as StaticFetchConfig<T, TransformData, UrlType>; // Changed cast
378385
}

0 commit comments

Comments
 (0)