Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: throw type error when skipToken is present in suspense query #8082

Merged
merged 24 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f25720b
refactor: handle type error when skipToken is present in suspense query
gwansikk Sep 21, 2024
ca9bf3d
test(react-query): add skipToken test for query hooks
gwansikk Sep 22, 2024
b91921e
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Sep 22, 2024
ed0e60f
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 3, 2024
41a9096
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 4, 2024
2d86422
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 5, 2024
dfa9d1a
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 8, 2024
73254d6
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 9, 2024
5b02842
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 9, 2024
cc2e4f9
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 9, 2024
8a93abf
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 9, 2024
91c8ffd
fix: merge form main
gwansikk Oct 9, 2024
80fb698
ci: apply automated fixes
autofix-ci[bot] Oct 9, 2024
0cc01cd
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 9, 2024
47653b1
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 10, 2024
9372c8b
feat(react-query): display “skipToken is not allowed” message in susp…
gwansikk Oct 10, 2024
2563143
feat(react-query): display “skipToken is not allowed” message in susp…
gwansikk Oct 10, 2024
aa7d780
feat(react-query): display “skipToken is not allowed” message in susp…
gwansikk Oct 10, 2024
c8f16bc
fix(react-query): update error message in useSuspenseInfiniteQuery
gwansikk Oct 10, 2024
b5bd8a9
Merge branch 'main' into react-query/exclude-suspense-skiptoken
gwansikk Oct 11, 2024
907d39f
Merge branch 'main' into react-query/exclude-suspense-skiptoken
TkDodo Oct 11, 2024
b7cd4b1
test(react-query): add test case
gwansikk Oct 11, 2024
7f61e8f
Merge branch 'main' into react-query/exclude-suspense-skiptoken
TkDodo Oct 11, 2024
f9aa558
Merge branch 'main' into react-query/exclude-suspense-skiptoken
TkDodo Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expectTypeOf, it, test } from 'vitest'
import { QueryClient, dataTagSymbol } from '@tanstack/query-core'
import { QueryClient, dataTagSymbol, skipToken } from '@tanstack/query-core'
import { infiniteQueryOptions } from '../infiniteQueryOptions'
import { useInfiniteQuery } from '../useInfiniteQuery'
import { useSuspenseInfiniteQuery } from '../useSuspenseInfiniteQuery'
Expand Down Expand Up @@ -134,6 +134,18 @@ describe('infiniteQueryOptions', () => {
InfiniteData<string, unknown> | undefined
>()
})
it('should throw a type error when using queryFn with skipToken in a suspense query', () => {
const options = infiniteQueryOptions({
queryKey: ['key'],
queryFn:
Math.random() > 0.5 ? skipToken : () => Promise.resolve('string'),
getNextPageParam: () => 1,
initialPageParam: 1,
})
// @ts-expect-error TS2345
const { data } = useSuspenseInfiniteQuery(options)
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, unknown>>()
})

test('should not be allowed to be passed to non-infinite query functions', () => {
const queryClient = new QueryClient()
Expand Down
10 changes: 7 additions & 3 deletions packages/react-query/src/__tests__/prefetch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
} from '..'
import { createQueryClient, queryKey, renderWithClient, sleep } from './utils'

import type { InfiniteData, UseInfiniteQueryOptions, UseQueryOptions } from '..'
import type {
InfiniteData,
UseSuspenseInfiniteQueryOptions,
UseSuspenseQueryOptions,
} from '..'
import type { Mock } from 'vitest'

const generateQueryFn = (data: string) =>
Expand Down Expand Up @@ -56,7 +60,7 @@ describe('usePrefetchQuery', () => {
const queryClient = createQueryClient({ queryCache })

function Suspended<TData = unknown>(props: {
queryOpts: UseQueryOptions<TData, Error, TData, Array<string>>
queryOpts: UseSuspenseQueryOptions<TData, Error, TData, Array<string>>
children?: React.ReactNode
}) {
const state = useSuspenseQuery(props.queryOpts)
Expand Down Expand Up @@ -303,7 +307,7 @@ describe('usePrefetchInfiniteQuery', () => {
const Fallback = vi.fn().mockImplementation(() => <div>Loading...</div>)

function Suspended<T = unknown>(props: {
queryOpts: UseInfiniteQueryOptions<
queryOpts: UseSuspenseInfiniteQueryOptions<
T,
Error,
InfiniteData<T>,
Expand Down
10 changes: 10 additions & 0 deletions packages/react-query/src/__tests__/queryOptions.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ describe('queryOptions', () => {
expectTypeOf(data).toEqualTypeOf<unknown>()
})

it('should throw a type error when using queryFn with skipToken in a suspense query', () => {
const options = queryOptions({
queryKey: ['key'],
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
})
// @ts-expect-error TS2345
const { data } = useSuspenseQuery(options)
expectTypeOf(data).toEqualTypeOf<number>()
})

it('should return the proper type when passed to QueriesObserver', () => {
const options = queryOptions({
queryKey: ['key'],
Expand Down
40 changes: 29 additions & 11 deletions packages/react-query/src/__tests__/suspense.test-d.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expectTypeOf, it } from 'vitest'
import { skipToken } from '@tanstack/query-core'
import { useSuspenseQuery } from '../useSuspenseQuery'
import { useSuspenseInfiniteQuery } from '../useSuspenseInfiniteQuery'
import type { UseSuspenseQueryOptions } from '..'
import type { InfiniteData } from '@tanstack/query-core'

describe('useSuspenseQuery', () => {
Expand All @@ -23,6 +23,20 @@ describe('useSuspenseQuery', () => {
expectTypeOf(status).toEqualTypeOf<'error' | 'success'>()
})

it('should not allow skipToken in queryFn', () => {
useSuspenseQuery({
queryKey: ['key'],
// @ts-expect-error
queryFn: skipToken,
})

useSuspenseQuery({
queryKey: ['key'],
// @ts-expect-error
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
})
})

it('should not allow placeholderData, enabled or throwOnError props', () => {
useSuspenseQuery({
queryKey: ['key'],
Expand Down Expand Up @@ -70,6 +84,20 @@ describe('useSuspenseInfiniteQuery', () => {
expectTypeOf(data).toEqualTypeOf<InfiniteData<number, unknown>>()
})

it('should not allow skipToken in queryFn', () => {
useSuspenseInfiniteQuery({
queryKey: ['key'],
// @ts-expect-error
queryFn: skipToken,
})

useSuspenseInfiniteQuery({
queryKey: ['key'],
// @ts-expect-error
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
})
})

it('should not have pending status', () => {
const { status } = useSuspenseInfiniteQuery({
queryKey: ['key'],
Expand Down Expand Up @@ -122,14 +150,4 @@ describe('useSuspenseInfiniteQuery', () => {
// @ts-expect-error TS2339
query.isPlaceholderData
})

it('should not accept skipToken type for queryFn in useSuspenseQuery', () => {
const query: UseSuspenseQueryOptions = {
// @ts-expect-error
queryFn: skipToken,
queryKey: [1],
}

return query
})
})
59 changes: 41 additions & 18 deletions packages/react-query/src/__tests__/useSuspenseQueries.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,47 @@ describe('UseSuspenseQueries config object overload', () => {
expectTypeOf(data).toEqualTypeOf<{ wow: boolean }>()
})

it('should not allow skipToken in queryFn', () => {
useSuspenseQueries({
queries: [
{
queryKey: ['key'],
// @ts-expect-error
queryFn: skipToken,
},
],
})

useSuspenseQueries({
queries: [
{
queryKey: ['key'],
// @ts-expect-error
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
},
],
})
})

it('TData should have correct type when conditional skipToken is passed', () => {
const queryResults = useSuspenseQueries({
queries: [
{
queryKey: ['withSkipToken'],
// @ts-expect-error
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
},
],
})

const firstResult = queryResults[0]

expectTypeOf(firstResult).toEqualTypeOf<
UseSuspenseQueryResult<number, Error>
>()
expectTypeOf(firstResult.data).toEqualTypeOf<number>()
})

describe('custom hook', () => {
it('should allow custom hooks using UseQueryOptions', () => {
type Data = string
Expand All @@ -113,22 +154,4 @@ describe('UseSuspenseQueries config object overload', () => {
expectTypeOf(data).toEqualTypeOf<Data>()
})
})

it('TData should have correct type when conditional skipToken is passed', () => {
const queryResults = useSuspenseQueries({
queries: [
{
queryKey: ['withSkipToken'],
queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5),
},
],
})

const firstResult = queryResults[0]

expectTypeOf(firstResult).toEqualTypeOf<
UseSuspenseQueryResult<number, Error>
>()
expectTypeOf(firstResult.data).toEqualTypeOf<number>()
})
})
2 changes: 2 additions & 0 deletions packages/react-query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ export { queryOptions } from './queryOptions'
export type {
DefinedInitialDataOptions,
UndefinedInitialDataOptions,
UnusedSkipTokenOptions,
} from './queryOptions'
export { infiniteQueryOptions } from './infiniteQueryOptions'
export type {
DefinedInitialDataInfiniteOptions,
UndefinedInitialDataInfiniteOptions,
UnusedSkipTokenInfiniteOptions,
} from './infiniteQueryOptions'
export {
QueryClientContext,
Expand Down
56 changes: 56 additions & 0 deletions packages/react-query/src/infiniteQueryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type {
DefaultError,
InfiniteData,
InitialDataFunction,
OmitKeyof,
QueryKey,
SkipToken,
} from '@tanstack/query-core'
import type { UseInfiniteQueryOptions } from './types'

Expand All @@ -29,6 +31,36 @@ export type UndefinedInitialDataInfiniteOptions<
>
}

export type UnusedSkipTokenInfiniteOptions<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> = OmitKeyof<
UseInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryFnData,
TQueryKey,
TPageParam
>,
'queryFn'
> & {
queryFn: Exclude<
UseInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryFnData,
TQueryKey,
TPageParam
>['queryFn'],
SkipToken
>
}

type NonUndefinedGuard<T> = T extends undefined ? never : T

export type DefinedInitialDataInfiniteOptions<
Expand Down Expand Up @@ -75,6 +107,30 @@ export function infiniteQueryOptions<
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
}

export function infiniteQueryOptions<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: UnusedSkipTokenInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
): UnusedSkipTokenInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
}

export function infiniteQueryOptions<
TQueryFnData,
TError = DefaultError,
Expand Down
28 changes: 28 additions & 0 deletions packages/react-query/src/queryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import type {
DataTag,
DefaultError,
InitialDataFunction,
OmitKeyof,
QueryKey,
SkipToken,
} from '@tanstack/query-core'
import type { UseQueryOptions } from './types'

Expand All @@ -18,6 +20,21 @@ export type UndefinedInitialDataOptions<
| NonUndefinedGuard<TQueryFnData>
}

export type UnusedSkipTokenOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = OmitKeyof<
UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
'queryFn'
> & {
queryFn: Exclude<
UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>['queryFn'],
SkipToken
>
}

type NonUndefinedGuard<T> = T extends undefined ? never : T

export type DefinedInitialDataOptions<
Expand All @@ -42,6 +59,17 @@ export function queryOptions<
queryKey: DataTag<TQueryKey, TQueryFnData>
}

export function queryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: UnusedSkipTokenOptions<TQueryFnData, TError, TData, TQueryKey>,
): UnusedSkipTokenOptions<TQueryFnData, TError, TData, TQueryKey> & {
queryKey: DataTag<TQueryKey, TQueryFnData>
}

export function queryOptions<
TQueryFnData = unknown,
TError = DefaultError,
Expand Down
26 changes: 22 additions & 4 deletions packages/react-query/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
QueryKey,
QueryObserverOptions,
QueryObserverResult,
SkipToken,
} from '@tanstack/query-core'

export interface UseBaseQueryOptions<
Expand Down Expand Up @@ -47,8 +48,13 @@ export interface UseSuspenseQueryOptions<
TQueryKey extends QueryKey = QueryKey,
> extends OmitKeyof<
UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
'enabled' | 'throwOnError' | 'placeholderData'
> {}
'queryFn' | 'enabled' | 'throwOnError' | 'placeholderData'
> {
queryFn: Exclude<
UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>['queryFn'],
SkipToken
>
}

export interface UseInfiniteQueryOptions<
TQueryFnData = unknown,
Expand Down Expand Up @@ -85,8 +91,20 @@ export interface UseSuspenseInfiniteQueryOptions<
TQueryKey,
TPageParam
>,
'enabled' | 'throwOnError' | 'placeholderData'
> {}
'queryFn' | 'enabled' | 'throwOnError' | 'placeholderData'
> {
queryFn: Exclude<
UseInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryData,
TQueryKey,
TPageParam
>['queryFn'],
SkipToken
>
}

export type UseBaseQueryResult<
TData = unknown,
Expand Down
Loading
Loading