Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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: 8 additions & 2 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,17 @@ export interface InfiniteQueryObserverSuccessResult<
status: 'success'
}

export type DefinedInfiniteQueryObserverResult<
TData = unknown,
TError = unknown,
> =
| InfiniteQueryObserverRefetchErrorResult<TData, TError>
| InfiniteQueryObserverSuccessResult<TData, TError>

export type InfiniteQueryObserverResult<TData = unknown, TError = unknown> =
| DefinedInfiniteQueryObserverResult<TData, TError>
| InfiniteQueryObserverLoadingErrorResult<TData, TError>
| InfiniteQueryObserverLoadingResult<TData, TError>
| InfiniteQueryObserverRefetchErrorResult<TData, TError>
| InfiniteQueryObserverSuccessResult<TData, TError>

export type MutationKey = readonly unknown[]

Expand Down
13 changes: 13 additions & 0 deletions packages/react-query/src/__tests__/infiniteQueryOptions.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { infiniteQueryOptions } from '../infiniteQueryOptions'

describe('infiniteQueryOptions', () => {
it('should return the object received as a parameter without any modification.', () => {
const object = {
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
getNextPageParam: () => null,
} as const

expect(infiniteQueryOptions(object)).toStrictEqual(object)
})
})
111 changes: 111 additions & 0 deletions packages/react-query/src/__tests__/infiniteQueryOptions.types.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { expectTypeOf } from 'expect-type'
import {
type InfiniteData,
type UseInfiniteQueryResult,
useInfiniteQuery,
useQueryClient,
} from '@tanstack/react-query'

import { useSuspenseInfiniteQuery } from '../useSuspenseInfiniteQuery'
import { infiniteQueryOptions } from '../infiniteQueryOptions'
import { doNotExecute } from './utils'
import type {
DefinedUseInfiniteQueryResult,
UseSuspenseInfiniteQueryResult,
} from '../types'

const infiniteQuery = {
options: () =>
infiniteQueryOptions({
queryKey: ['key', 1] as const,
queryFn: () => Promise.resolve({ field: 'success' }),
}),
optionsWithInitialData: () =>
infiniteQueryOptions({
queryKey: ['key', 2] as const,
queryFn: () => Promise.resolve({ field: 'success' }),
initialData: () => ({ pageParams: [], pages: [{ field: 'success' }] }),
}),
}

describe('infiniteQueryOptions', () => {
it('should be used with useInfiniteQuery', () => {
doNotExecute(() => {
expectTypeOf(useInfiniteQuery(infiniteQuery.options())).toEqualTypeOf<
UseInfiniteQueryResult<{ field: string }>
>()

expectTypeOf(
useInfiniteQuery({
...infiniteQuery.options(),
select: (data) => ({
pages: data.pages.map(({ field }) => field),
pageParams: data.pageParams,
}),
}),
).toEqualTypeOf<UseInfiniteQueryResult<string>>()

expectTypeOf(
useInfiniteQuery(infiniteQuery.optionsWithInitialData()),
).toEqualTypeOf<DefinedUseInfiniteQueryResult<{ field: string }>>()

expectTypeOf(
useInfiniteQuery({
...infiniteQuery.optionsWithInitialData(),
select: (data) => ({
pages: data.pages.map(({ field }) => field),
pageParams: data.pageParams,
}),
}),
).toEqualTypeOf<DefinedUseInfiniteQueryResult<string>>()

expectTypeOf(
useInfiniteQuery({
queryKey: ['key', 2] as const,
queryFn: () => Promise.resolve({ field: 'success' }),
initialData: () => ({
pages: [{ field: 'success' }],
pageParams: [],
}),
select: (data) => ({
pages: data.pages.map(({ field }) => field),
pageParams: data.pageParams,
}),
}),
).toEqualTypeOf<DefinedUseInfiniteQueryResult<string>>()
})
})
it('should be used with useSuspenseInfiniteQuery', () => {
doNotExecute(() => {
expectTypeOf(
useSuspenseInfiniteQuery(infiniteQuery.options()),
).toEqualTypeOf<UseSuspenseInfiniteQueryResult<{ field: string }>>()

expectTypeOf(
useSuspenseInfiniteQuery({
...infiniteQuery.options(),
select: (data) => ({
pages: data.pages.map(({ field }) => field),
pageParams: data.pageParams,
}),
}),
).toEqualTypeOf<UseSuspenseInfiniteQueryResult<string>>()
})
})
it('should be used with useQueryClient', () => {
doNotExecute(async () => {
const queryClient = useQueryClient()

queryClient.invalidateQueries(infiniteQuery.options())
queryClient.resetQueries(infiniteQuery.options())
queryClient.removeQueries(infiniteQuery.options())
queryClient.cancelQueries(infiniteQuery.options())
queryClient.prefetchQuery(infiniteQuery.options())
queryClient.refetchQueries(infiniteQuery.options())

expectTypeOf(
await queryClient.fetchQuery(infiniteQuery.options()),
).toEqualTypeOf<InfiniteData<{ field: string }>>()
})
})
})
15 changes: 8 additions & 7 deletions packages/react-query/src/__tests__/queryOptions.types.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ const queryFn = () => Promise.resolve({ field: 'success' })
describe('queryOptions', () => {
it('should be used with useQuery', () => {
doNotExecute(() => {
const dd = useQuery(
queryOptions({
queryKey,
queryFn,
}),
)
expectTypeOf(dd).toEqualTypeOf<UseQueryResult<{ field: string }>>()
expectTypeOf(
useQuery(
queryOptions({
queryKey,
queryFn,
}),
),
).toEqualTypeOf<UseQueryResult<{ field: string }>>()
expectTypeOf(
useQuery({
...queryOptions({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { expectTypeOf } from 'expect-type'
import { infiniteQueryOptions, useSuspenseInfiniteQuery } from '..'
import { doNotExecute, sleep } from './utils'
import type { UseSuspenseInfiniteQueryResult } from '..'

import type { InfiniteData } from '@tanstack/react-query'

const queryKey = ['key'] as const
const queryFn = () => sleep(10).then(() => ({ text: 'response' }))

describe('useSuspenseInfiniteQuery', () => {
it('type check', () => {
doNotExecute(() => {
// @ts-expect-error no arg
useSuspenseInfiniteQuery()

useSuspenseInfiniteQuery({
queryKey,
queryFn,
// @ts-expect-error no suspense
suspense: boolean,
})
useSuspenseInfiniteQuery({
queryKey,
queryFn,
// @ts-expect-error no useErrorBoundary
useErrorBoundary: boolean,
})
useSuspenseInfiniteQuery({
queryKey,
queryFn,
// @ts-expect-error no enabled
enabled: boolean,
})
useSuspenseInfiniteQuery({
queryKey,
queryFn,
// @ts-expect-error no placeholderData
placeholderData: 'placeholder',
})
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
useSuspenseInfiniteQuery({
queryKey,
queryFn,
// @ts-expect-error no isPlaceholderData
}).isPlaceholderData
useSuspenseInfiniteQuery({
queryKey,
queryFn,
//@ts-expect-error no networkMode
networkMode: 'always',
})

const infiniteQuery = useSuspenseInfiniteQuery({ queryKey, queryFn })
expectTypeOf(infiniteQuery).toEqualTypeOf<
UseSuspenseInfiniteQueryResult<{ text: string }>
>()
expectTypeOf(infiniteQuery.data).toEqualTypeOf<
InfiniteData<{ text: string }>
>()
expectTypeOf(infiniteQuery.status).toEqualTypeOf<'error' | 'success'>()

const selectedInfiniteQuery = useSuspenseInfiniteQuery({
queryKey,
queryFn,
select: (data) => ({
pages: data.pages.map(({ text }) => text),
pageParams: data.pageParams,
}),
})
expectTypeOf(selectedInfiniteQuery).toEqualTypeOf<
UseSuspenseInfiniteQueryResult<string>
>()
expectTypeOf(selectedInfiniteQuery.data).toEqualTypeOf<
InfiniteData<string>
>()
expectTypeOf(selectedInfiniteQuery.status).toEqualTypeOf<
'error' | 'success'
>()

const options = infiniteQueryOptions({
queryKey,
queryFn,
})

const infiniteQueryWithOptions = useSuspenseInfiniteQuery(options)
expectTypeOf(infiniteQueryWithOptions).toEqualTypeOf<
UseSuspenseInfiniteQueryResult<{ text: string }>
>()
expectTypeOf(infiniteQueryWithOptions.data).toEqualTypeOf<
InfiniteData<{ text: string }>
>()
expectTypeOf(infiniteQueryWithOptions.status).toEqualTypeOf<
'error' | 'success'
>()

const selectedInfiniteQueryWithOptions = useSuspenseInfiniteQuery({
...options,
select: (data) => ({
pages: data.pages.map(({ text }) => text),
pageParams: data.pageParams,
}),
})
expectTypeOf(selectedInfiniteQueryWithOptions).toEqualTypeOf<
UseSuspenseInfiniteQueryResult<string>
>()
expectTypeOf(selectedInfiniteQueryWithOptions.data).toEqualTypeOf<
InfiniteData<string>
>()
expectTypeOf(selectedInfiniteQueryWithOptions.status).toEqualTypeOf<
'error' | 'success'
>()
})
})
})
6 changes: 6 additions & 0 deletions packages/react-query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { useQueries } from './useQueries'
export type { QueriesResults, QueriesOptions } from './useQueries'
export { useQuery } from './useQuery'
export { useSuspenseQuery } from './useSuspenseQuery'
export { useSuspenseInfiniteQuery } from './useSuspenseInfiniteQuery'
export { useSuspenseQueries } from './useSuspenseQueries'
export type {
SuspenseQueriesResults,
Expand All @@ -22,6 +23,11 @@ export type {
DefinedInitialDataOptions,
UndefinedInitialDataOptions,
} from './queryOptions'
export { infiniteQueryOptions } from './infiniteQueryOptions'
export type {
DefinedInitialDataInfiniteOptions,
UndefinedInitialDataInfiniteOptions,
} from './infiniteQueryOptions'
export {
defaultContext,
QueryClientProvider,
Expand Down
95 changes: 95 additions & 0 deletions packages/react-query/src/infiniteQueryOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import type { UseInfiniteQueryOptions } from './types'
import type {
InfiniteData,
NonUndefinedGuard,
OmitKeyof,
QueryKey,
WithRequired,
} from '@tanstack/query-core'

type UseInfiniteQueryOptionsOmitted<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = OmitKeyof<
UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>,
'onSuccess' | 'onError' | 'onSettled' | 'refetchInterval'
>

type ProhibitedInfiniteQueryOptionsKeyInV5 = keyof Pick<
UseInfiniteQueryOptionsOmitted,
'useErrorBoundary' | 'suspense'
>

export type UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = UseInfiniteQueryOptionsOmitted<TQueryFnData, TError, TData, TQueryKey> & {
initialData?: undefined
}

export type DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = UseInfiniteQueryOptionsOmitted<TQueryFnData, TError, TData, TQueryKey> & {
initialData:
| NonUndefinedGuard<InfiniteData<TQueryFnData>>
| (() => NonUndefinedGuard<InfiniteData<TQueryFnData>>)
| undefined
}

export function infiniteQueryOptions<
TQueryFnData,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: WithRequired<
OmitKeyof<
DefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey>,
ProhibitedInfiniteQueryOptionsKeyInV5
>,
'queryKey'
>,
): WithRequired<
OmitKeyof<
DefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey>,
ProhibitedInfiniteQueryOptionsKeyInV5
>,
'queryKey'
>

export function infiniteQueryOptions<
TQueryFnData,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: WithRequired<
OmitKeyof<
UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey
>,
ProhibitedInfiniteQueryOptionsKeyInV5
>,
'queryKey'
>,
): WithRequired<
OmitKeyof<
UndefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey>,
ProhibitedInfiniteQueryOptionsKeyInV5
>,
'queryKey'
>

export function infiniteQueryOptions(options: unknown) {
return options
}
Loading
Loading