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: handle type error when skipToken is present in suspense query #8082

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
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>()
})
})
56 changes: 56 additions & 0 deletions packages/react-query/src/infiniteQueryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import type {
DataTag,
DefaultError,
InfiniteData,
OmitKeyof,
QueryKey,
SkipToken,
} from '@tanstack/query-core'
import type { UseInfiniteQueryOptions } from './types'

Expand All @@ -23,6 +25,36 @@ export type UndefinedInitialDataInfiniteOptions<
initialData?: undefined
}

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 @@ -68,6 +100,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 @@ -15,6 +17,21 @@ export type UndefinedInitialDataOptions<
initialData?: undefined | InitialDataFunction<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 @@ -39,6 +56,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
8 changes: 1 addition & 7 deletions packages/react-query/src/useSuspenseInfiniteQuery.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client'
import { InfiniteQueryObserver, skipToken } from '@tanstack/query-core'
import { InfiniteQueryObserver } from '@tanstack/query-core'
import { useBaseQuery } from './useBaseQuery'
import { defaultThrowOnError } from './suspense'
import type {
Expand Down Expand Up @@ -32,12 +32,6 @@ export function useSuspenseInfiniteQuery<
>,
queryClient?: QueryClient,
): UseSuspenseInfiniteQueryResult<TData, TError> {
if (process.env.NODE_ENV !== 'production') {
if (options.queryFn === skipToken) {
console.error('skipToken is not allowed for useSuspenseInfiniteQuery')
}
}

return useBaseQuery(
{
...options,
Expand Down
7 changes: 0 additions & 7 deletions packages/react-query/src/useSuspenseQueries.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use client'
import { skipToken } from '@tanstack/query-core'
import { useQueries } from './useQueries'
import { defaultThrowOnError } from './suspense'
import type { UseSuspenseQueryOptions, UseSuspenseQueryResult } from './types'
Expand Down Expand Up @@ -192,12 +191,6 @@ export function useSuspenseQueries<
{
...options,
queries: options.queries.map((query) => {
if (process.env.NODE_ENV !== 'production') {
if (query.queryFn === skipToken) {
console.error('skipToken is not allowed for useSuspenseQueries')
}
}

return {
...query,
suspense: true,
Expand Down
Loading
Loading