Skip to content

Commit e2dd554

Browse files
committed
chore: Started work on interface rewrite
1 parent 9285a0c commit e2dd554

File tree

1 file changed

+294
-0
lines changed

1 file changed

+294
-0
lines changed

src/types-2.ts

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
import { SerializedError } from "@reduxjs/toolkit";
2+
import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query";
3+
import { ReactElement } from "react";
4+
import { useCreateQuery } from "./createQuery";
5+
6+
/** Result of a RTK useQuery hook */
7+
export type UseQueryResult<T> = {
8+
// Base query state
9+
/** Arguments passed to the query */
10+
originalArgs?: unknown;
11+
/** The latest returned result regardless of hook arg, if present */
12+
data?: T;
13+
/** The latest returned result for the current hook arg, if present */
14+
currentData?: T;
15+
/** Error result if present */
16+
error?: unknown;
17+
/** A string generated by RTK Query */
18+
requestId?: string;
19+
/** The name of the given endpoint for the query */
20+
endpointName?: string;
21+
/** Timestamp for when the query was initiated */
22+
startedTimeStamp?: number;
23+
/** Timestamp for when the query was completed */
24+
fulfilledTimeStamp?: number;
25+
26+
// Derived request status booleans
27+
/** Query has not started yet */
28+
isUninitialized: boolean;
29+
/** Query is currently loading for the first time. No data yet. */
30+
isLoading: boolean;
31+
/** Query is currently fetching, but might have data from an earlier request. */
32+
isFetching: boolean;
33+
/** Query has data from a successful load */
34+
isSuccess: boolean;
35+
/** Query is currently in an "error" state */
36+
isError: boolean;
37+
38+
/** A function to force refetch the query */
39+
refetch: () => void;
40+
};
41+
42+
/** _X are types that are extended from in the generics */
43+
export type _Q = Record<string, UseQueryResult<unknown>>;
44+
export type _D = Record<string, UseQueryResult<unknown>>;
45+
export type _E = unknown;
46+
export type _P = Record<string, unknown>;
47+
export type _R = unknown;
48+
49+
export type MakeDataRequired<T extends _Q> = {
50+
// @ts-ignore: TS2536: Type '"data"' cannot be used to index type 'T[K]'.
51+
[K in keyof T]: T[K] & { data: NonNullable<T[K]["data"]> };
52+
};
53+
54+
export type DataShape<
55+
Q extends _Q,
56+
D extends _D,
57+
E extends _E
58+
> = {
59+
queries?: Q;
60+
deferredQueries?: D;
61+
payload?: E;
62+
};
63+
64+
/** Use: `(...args: OptionalGenericArg<T>) => void;`
65+
* Allows either `T` or `none` for the parameter
66+
*/
67+
export type OptionalGenericArg<T> = T extends never ? [] : [T];
68+
69+
export type LoaderTransformFunction<
70+
Q extends _Q,
71+
D extends _D,
72+
E extends _E,
73+
R extends unknown
74+
> = (data: DataShape<MakeDataRequired<Q>, D, E>) => R;
75+
76+
export type CreateUseLoaderArgs<
77+
Q extends _Q,
78+
D extends _D,
79+
E extends _E,
80+
R extends _R,
81+
A = never
82+
> = {
83+
/** Should return a list of RTK useQuery results.
84+
* Example:
85+
* ```typescript
86+
* (args: Args) => ({
87+
* queries: {
88+
* pokemon: useGetPokemonQuery(args.pokemonId),
89+
* }
90+
* })
91+
* ```
92+
*/
93+
useQuery: (
94+
...args: OptionalGenericArg<A>
95+
) => DataShape<Q, D, E>;
96+
/** Transforms the output of the queries */
97+
transform?: (data: DataShape<Q, D, E>) => R;
98+
};
99+
100+
export type UseLoader<A, R> = (
101+
...args: OptionalGenericArg<A>
102+
) => UseQueryResult<R>;
103+
104+
export type ComponentWithLoaderData<
105+
P extends Record<string, any>,
106+
R extends unknown
107+
> = (props: P, loaderData: R) => ReactElement;
108+
109+
/** Use: `InferLoaderData<typeof loader>`. Returns the return-value of the given loader's aggregated query. */
110+
export type InferLoaderData<T> = T extends Loader<
111+
any,
112+
infer X,
113+
any,
114+
any
115+
>
116+
? X
117+
: T extends Loader<never, infer Y, any, any>
118+
? Y
119+
: T extends Loader<any, infer Z, never, any>
120+
? Z
121+
: never;
122+
123+
export type Component<P extends Record<string, any>> = (
124+
props: P
125+
) => ReactElement;
126+
127+
export type WhileFetchingArgs<
128+
P extends unknown,
129+
R extends unknown
130+
> = {
131+
/** Will be prepended before the component while the query is fetching */
132+
prepend?: (props: P, data?: R) => ReactElement;
133+
/** Will be appended after the component while the query is fetching */
134+
append?: (props: P, data?: R) => ReactElement;
135+
};
136+
137+
export type CustomLoaderProps<T = unknown> = {
138+
/** What the loader requests be rendered while fetching data */
139+
onFetching?: React.ReactElement;
140+
/** What the loader requests be rendered while fetching data */
141+
whileFetching?: {
142+
/** Should be appended to the success result while fetching */
143+
append?: React.ReactElement;
144+
/** Should be prepended to the success result while fetching */
145+
prepend?: React.ReactElement;
146+
};
147+
/** What the loader requests be rendered when data is available */
148+
onSuccess: (data: T) => React.ReactElement;
149+
/** What the loader requests be rendered when the query fails */
150+
onError?: (
151+
error: SerializedError | FetchBaseQueryError
152+
) => JSX.Element;
153+
/** What the loader requests be rendered while loading data */
154+
onLoading?: React.ReactElement;
155+
/** The joined query for the loader */
156+
query: UseQueryResult<T>;
157+
};
158+
159+
export type CreateLoaderArgs<
160+
P extends unknown,
161+
Q extends _Q,
162+
D extends _D,
163+
E extends _E,
164+
R extends unknown = MakeDataRequired<Q>,
165+
A = never
166+
> = Partial<CreateUseLoaderArgs<Q, D, E, R, A>> & {
167+
/** Generates an argument for the `queries` based on component props */
168+
queriesArg?: (props: P) => A;
169+
/** Determines what to render while loading (with no data to fallback on) */
170+
onLoading?: (props: P) => ReactElement;
171+
/** Determines what to render when query fails. */
172+
onError?: (
173+
props: P,
174+
error: FetchBaseQueryError | SerializedError,
175+
joinedQuery: UseQueryResult<undefined>
176+
) => ReactElement;
177+
/** @deprecated Using onFetching might result in loss of internal state. Use `whileFetching` instead, or pass the query to the component */
178+
onFetching?: (
179+
props: P,
180+
renderBody: () => ReactElement
181+
) => ReactElement;
182+
/** Determines what to render besides success-result while query is fetching. */
183+
whileFetching?: WhileFetchingArgs<P, R>;
184+
/** The component to use to switch between rendering the different query states. */
185+
loaderComponent?: Component<CustomLoaderProps>;
186+
};
187+
188+
export type Loader<
189+
P extends unknown,
190+
R extends unknown,
191+
Q extends _Q = _Q,
192+
D extends _D = _D,
193+
A = never
194+
> = {
195+
/** A hook that runs all queries and returns aggregated result */
196+
useLoader: UseLoader<A, R>;
197+
/** Generates an argument for the `queries` based on component props */
198+
queriesArg?: (props: P) => A;
199+
/** Determines what to render while loading (with no data to fallback on) */
200+
onLoading?: (props: P) => ReactElement;
201+
/** Determines what to render when query fails. */
202+
onError?: (
203+
props: P,
204+
error: SerializedError | FetchBaseQueryError,
205+
joinedQuery: UseQueryResult<undefined>
206+
) => ReactElement;
207+
/** @deprecated Using onFetching might result in loss of internal state. Use `whileFetching` instead, or pass the query to the component */
208+
onFetching?: (
209+
props: P,
210+
renderBody: () => ReactElement
211+
) => ReactElement;
212+
/** Determines what to render besides success-result while query is fetching. */
213+
whileFetching?: WhileFetchingArgs<P, R>;
214+
/** Returns a new `Loader` extended from this `Loader`, with given overrides. */
215+
extend: <
216+
Qb extends _Q = Q,
217+
Db extends _D = _Q,
218+
Pb extends unknown = P,
219+
Rb extends unknown = Qb extends Q
220+
? R extends never
221+
? Q
222+
: R
223+
: MakeDataRequired<Qb>,
224+
Ab = A
225+
>(
226+
newLoader: Partial<CreateLoaderArgs<Pb, Qb, Db, Rb, Ab>>
227+
) => Loader<
228+
Pb,
229+
Rb,
230+
Qb extends never ? Q : Qb,
231+
Db extends never ? D : Db,
232+
Ab
233+
>;
234+
/** The component to use to switch between rendering the different query states. */
235+
LoaderComponent: Component<CustomLoaderProps>;
236+
};
237+
238+
export type CreateQueryGetter<T extends unknown> =
239+
() => Promise<T>;
240+
241+
export type CreateQueryReducerAction<T extends unknown> =
242+
| {
243+
type: "load";
244+
}
245+
| {
246+
type: "fetch";
247+
}
248+
| {
249+
type: "error";
250+
payload: {
251+
error: unknown;
252+
};
253+
}
254+
| {
255+
type: "success";
256+
payload: {
257+
data: T;
258+
};
259+
};
260+
261+
/************************************************/
262+
/* Legacy/unused, for backwards compatibility */
263+
/************************************************/
264+
export type WithLoaderArgs<
265+
P extends unknown,
266+
R extends unknown,
267+
A = never
268+
> = Loader<P, R, _Q, _Q, A>;
269+
270+
const _createLoaderTypeTest = <
271+
P extends unknown,
272+
Q extends _Q,
273+
D extends _D,
274+
E extends _E,
275+
R extends unknown = MakeDataRequired<Q>,
276+
A = never
277+
>(
278+
args: CreateLoaderArgs<P, Q, D, E, R>
279+
): Loader<P, R, Q, D, A> => {
280+
return {} as Loader<P, R, Q, D, A>;
281+
};
282+
283+
const asd = _createLoaderTypeTest({
284+
useQuery: () => {
285+
return {
286+
queries: {
287+
test: useCreateQuery(async () => "foo" as const),
288+
},
289+
deferredQueries: {
290+
best: useCreateQuery(async () => "bar" as const),
291+
},
292+
};
293+
},
294+
});

0 commit comments

Comments
 (0)