Skip to content

Commit

Permalink
fix(useQueries): check for invalid types
Browse files Browse the repository at this point in the history
  • Loading branch information
artysidorenko committed Apr 22, 2022
1 parent ca70f08 commit 10f5585
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/reactjs/tests/useQueries.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,50 @@ describe('useQueries', () => {
// @ts-expect-error (Page component is not rendered)
// eslint-disable-next-line
function Page() {
// Rejects queryFn that returns/resolved to undefined
// @ts-expect-error (queryFn must not return undefined)
useQueries({ queries: [{ queryKey: key1, queryFn: () => undefined }] })
useQueries({
queries: [
// @ts-expect-error (queryFn must not return undefined)
{ queryKey: key2, queryFn: () => Promise.resolve(undefined) },
],
})
useQueries({
// @ts-expect-error (queryFn must not return undefined)
queries: Array(50).map((_, i) => ({
queryKey: ['key', i] as const,
queryFn: () => Promise.resolve(undefined),
})),
})

// Rejects queryFn that always throws
useQueries({
queries: [
// @ts-expect-error (queryFn must not return undefined)
{
queryKey: key3,
queryFn: async () => {
throw new Error('')
},
},
],
})
// Accepts queryFn that *sometimes* throws
useQueries({
queries: [
{
queryKey: key3,
queryFn: async () => {
if (Math.random() > 0.1) {
throw new Error('')
}
return 'result'
},
},
],
})

// Array.map preserves TQueryFnData
const result1 = useQueries({
queries: Array(50).map((_, i) => ({
Expand Down
7 changes: 7 additions & 0 deletions src/reactjs/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type UseQueryOptionsForUseQueries<
TQueryKey extends QueryKey = QueryKey
> = Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'context'>

type InvalidQueryFn = QueryFunction<undefined | Promise<undefined> | Promise<undefined> | void | Promise<void>>

// Avoid TS depth-limit error in case of large array literal
type MAXIMUM_DEPTH = 20

Expand All @@ -40,6 +42,9 @@ type GetOptions<T> =
: T extends [infer TQueryFnData]
? UseQueryOptionsForUseQueries<TQueryFnData>
: // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided
T extends { queryFn?: InvalidQueryFn }
? never | 'queryFn must not return undefined'

This comment has been minimized.

Copy link
@artysidorenko

artysidorenko Apr 22, 2022

Author Owner

(the string is there just to make the type error message more informative, otherwise it's a real pain to figure out what's going on, because the error appears on the entire argument array)

:
T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
select: (data: any) => infer TData
Expand Down Expand Up @@ -100,6 +105,8 @@ export type QueriesOptions<
? T
: // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!
// use this to infer the param types in the case of Array.map() argument
T extends { queryFn: InvalidQueryFn }[]
? (never | 'queryFn must not return undefined')[] :
T extends UseQueryOptionsForUseQueries<
infer TQueryFnData,
infer TError,
Expand Down

0 comments on commit 10f5585

Please sign in to comment.