query
query copied to clipboard
remove overloads
context
useQuery
and friends have many overloads in TypeScript - different ways how the function can be invoked. As an example, let's look at useQuery
. You can call it in three different ways:
useQuery(queryKey, queryFn, options)
useQuery(queryKey, options)
useQuery(options)
The queryKey
is the only required property. The queryFn is optional because you might have defined it globally. If you use the syntax where you only pass one object in, the queryKey is also required.
Not only is this tough to maintain, type wise, it also requires a runtime check to see which type the first and the second parameter are to correctly create options. Internally, we only work with one options object.
Further, we started to add more overloads for features that are only doable with overloads. For example, if you pass initialData
, the return type of data
will not contain undefined
. Because initialData
can also be a function, we need another 3 overloads for each possibility to call useQuery
, resulting in 9 total overloads.
The useQuery.ts
file has 140 lines of code - only 3 of which are actual JavaScript.
Other functions suffer from the same problem, and overloads are also not consistent. For example, queryCache.findAll
has overloads, but mutationCache.findAll
does not.
proposal
- remove all overloads and only allow all functions to be called with a single signature - one object
detailed changes
- useQuery(key, fn, options)
+ useQuery({ queryKey, queryFn, ...options })
// ⬆️ queryKey must be required
- useInfiniteQuery(key, fn, options)
+ useInfiniteQuery({ queryKey, queryFn, ...options })
// ⬆️ queryKey must be required
- useMutation(fn, options)
+ useQuery({ mutationFn, ...options })
- useIsFetching(key, filters)
+ useIsFetching({ queryKey, ...filters })
- useIsMutating(key, filters)
+ useIsMutating({ mutationKey, ...filters })
- queryClient.isFetching(key, filters)
+ queryClient.isFetching({ queryKey, ...filters })
- queryClient.ensureQueryData(key, fn, options)
+ queryClient.ensureQueryData({ queryKey, queryFn, ...options })
// ⬆️ queryKey must be required
- queryClient.getQueriesData(key, filters)
+ queryClient.getQueriesData({ queryKey, ...filters })
- queryClient.setQueriesData(key, updater, filters, options)
+ queryClient.setQueriesData({ queryKey, ...filters }, updater, options)
- queryClient.removeQueries(key, filters)
+ queryClient.removeQueries({ queryKey, ...filters })
- queryClient.resetQueries(key, filters, options)
+ queryClient.resetQueries({ queryKey, ...filters }, options)
- queryClient.cancelQueries(key, filters, options)
+ queryClient.cancelQueries({ queryKey, ...filters }, options)
- queryClient.invalidateQueries(key, filters, options)
+ queryClient.invalidateQueries({ queryKey, ...filters }, options)
- queryClient.refetchQueries(key, filters, options)
+ queryClient.refetchQueries({ queryKey, ...filters }, options)
- queryClient.fetchQuery(key, fn, options)
+ queryClient.fetchQuery({ queryKey, queryFn, ...options })
- queryClient.prefetchQuery(key, fn, options)
+ queryClient.prefetchQuery({ queryKey, queryFn, ...options })
- queryClient.fetchInfiniteQuery(key, fn, options)
+ queryClient.fetchInfiniteQuery({ queryKey, queryFn, ...options })
- queryClient.prefetchInfiniteQuery(key, fn, options)
+ queryClient.prefetchInfiniteQuery({ queryKey, queryFn, ...options })
- queryCache.find(key, filters)
+ queryCache.find({ queryKey, ...filters })
// ⬆️ queryKey must be required
// `exact` could be omitted from possible filters and always set to `true` !
- queryCache.findAll(key, filters)
+ queryCache.findAll({ queryKey, ...filters })
Working on it 🫡
Hello, I wanted to make sure of something
queryClient.fetchQuery({ queryKey, queryFn, ...options })
queryClient.fetchInfiniteQuery({ queryKey, queryFn, ...options })
queryClient.prefetchQuery({ queryKey, queryFn, ...options })
queryClient.prefetchInfiniteQuery({ queryKey, queryFn, ...options })
queryCache.findAll({ queryKey, ...filters })
In these 5, is the queryKey
required?
Also, the PR will be big 😅 should I split it into multiple PRs? or just organize the commits messages?
I am almost there 😅 just need to remove the useMutation/useIsMutating overloads and It will be done
In these 5, is the queryKey required?
it's required for fetch and fetchInfinite, but not for findAll. In findAll, it's just one possible filter (part of the QueryFilters type). If you use QueryFilters as-is, it's fine.
Also, the PR will be big 😅 should I split it into multiple PRs? or just organize the commits messages?
One PR will be fine, thank you