Skip to content

Commit

Permalink
fix(react-query): useSuspenseQueries type not compatible with queryOp…
Browse files Browse the repository at this point in the history
…tion (#7194)

Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
  • Loading branch information
andykog and TkDodo committed Apr 2, 2024
1 parent 0123c80 commit f585bfe
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 2 deletions.
116 changes: 116 additions & 0 deletions packages/react-query/src/__tests__/useSuspenseQueries.test-d.tsx
@@ -0,0 +1,116 @@
import { describe, expectTypeOf, it } from 'vitest'
import { useSuspenseQueries } from '..'
import { queryOptions } from '../queryOptions'
import type { OmitKeyof } from '..'
import type { UseQueryOptions } from '../types'

describe('UseSuspenseQueries config object overload', () => {
it('TData should always be defined', () => {
const query1 = {
queryKey: ['key1'],
queryFn: () => {
return {
wow: true,
}
},
initialData: {
wow: false,
},
}

const query2 = {
queryKey: ['key2'],
queryFn: () => 'Query Data',
}

const queryResults = useSuspenseQueries({ queries: [query1, query2] })

const query1Data = queryResults[0].data
const query2Data = queryResults[1].data

expectTypeOf(query1Data).toEqualTypeOf<{ wow: boolean }>()
expectTypeOf(query2Data).toEqualTypeOf<string>()
})

it('TData should be defined when passed through queryOptions', () => {
const options = queryOptions({
queryKey: ['key'],
queryFn: () => {
return {
wow: true,
}
},
})
const queryResults = useSuspenseQueries({ queries: [options] })

const data = queryResults[0].data

expectTypeOf(data).toEqualTypeOf<{ wow: boolean }>()
})

it('it should be possible to define a different TData than TQueryFnData using select with queryOptions spread into useQuery', () => {
const query1 = queryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve(1),
select: (data) => data > 1,
})

const query2 = {
queryKey: ['key'],
queryFn: () => Promise.resolve(1),
select: (data: number) => data > 1,
}

const queryResults = useSuspenseQueries({ queries: [query1, query2] })
const query1Data = queryResults[0].data
const query2Data = queryResults[1].data

expectTypeOf(query1Data).toEqualTypeOf<boolean>()
expectTypeOf(query2Data).toEqualTypeOf<boolean>()
})

it('TData should have undefined in the union when initialData is provided as a function which can return undefined', () => {
const queryResults = useSuspenseQueries({
queries: [
{
queryKey: ['key'],
queryFn: () => {
return {
wow: true,
}
},
initialData: () => undefined as { wow: boolean } | undefined,
},
],
})

const data = queryResults[0].data

expectTypeOf(data).toEqualTypeOf<{ wow: boolean }>()
})

describe('custom hook', () => {
it('should allow custom hooks using UseQueryOptions', () => {
type Data = string

const useCustomQueries = (
options?: OmitKeyof<UseQueryOptions<Data>, 'queryKey' | 'queryFn'>,
) => {
return useSuspenseQueries({
queries: [
{
...options,
queryKey: ['todos-key'],
queryFn: () => Promise.resolve('data'),
},
],
})
}

const queryResults = useCustomQueries()
const data = queryResults[0].data

expectTypeOf(data).toEqualTypeOf<Data>()
})
})
})
6 changes: 4 additions & 2 deletions packages/react-query/src/useSuspenseQueries.ts
Expand Up @@ -78,7 +78,7 @@ type GetSuspenseResults<T> =
? UseSuspenseQueryResult<TQueryFnData>
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
queryFn?: QueryFunction<infer TQueryFnData, any> | SkipToken
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
Expand All @@ -87,7 +87,9 @@ type GetSuspenseResults<T> =
unknown extends TError ? DefaultError : TError
>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
queryFn?:
| QueryFunction<infer TQueryFnData, any>
| SkipToken
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseSuspenseQueryResult<
Expand Down

0 comments on commit f585bfe

Please sign in to comment.