@tanstack/react-query 5.24.8 → 5.26.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/build/codemods/coverage/clover.xml +2 -2
  2. package/build/codemods/coverage/index.html +1 -1
  3. package/build/codemods/coverage/utils/index.html +1 -1
  4. package/build/codemods/coverage/utils/index.js.html +1 -1
  5. package/build/codemods/coverage/utils/transformers/index.html +1 -1
  6. package/build/codemods/coverage/utils/transformers/query-cache-transformer.js.html +1 -1
  7. package/build/codemods/coverage/utils/transformers/query-client-transformer.js.html +1 -1
  8. package/build/codemods/coverage/utils/transformers/use-query-like-transformer.js.html +1 -1
  9. package/build/codemods/coverage/v4/index.html +1 -1
  10. package/build/codemods/coverage/v4/key-transformation.js.html +1 -1
  11. package/build/codemods/coverage/v4/replace-import-specifier.js.html +1 -1
  12. package/build/codemods/coverage/v4/utils/replacers/index.html +1 -1
  13. package/build/codemods/coverage/v4/utils/replacers/key-replacer.js.html +1 -1
  14. package/build/codemods/coverage/v5/is-loading/index.html +1 -1
  15. package/build/codemods/coverage/v5/is-loading/is-loading.js.html +1 -1
  16. package/build/codemods/coverage/v5/keep-previous-data/index.html +1 -1
  17. package/build/codemods/coverage/v5/keep-previous-data/keep-previous-data.js.html +1 -1
  18. package/build/codemods/coverage/v5/keep-previous-data/utils/already-has-placeholder-data-property.js.html +1 -1
  19. package/build/codemods/coverage/v5/keep-previous-data/utils/index.html +1 -1
  20. package/build/codemods/coverage/v5/remove-overloads/index.html +1 -1
  21. package/build/codemods/coverage/v5/remove-overloads/remove-overloads.js.html +1 -1
  22. package/build/codemods/coverage/v5/remove-overloads/transformers/filter-aware-usage-transformer.js.html +1 -1
  23. package/build/codemods/coverage/v5/remove-overloads/transformers/index.html +1 -1
  24. package/build/codemods/coverage/v5/remove-overloads/transformers/query-fn-aware-usage-transformer.js.html +1 -1
  25. package/build/codemods/coverage/v5/remove-overloads/utils/index.html +1 -1
  26. package/build/codemods/coverage/v5/remove-overloads/utils/index.js.html +1 -1
  27. package/build/codemods/coverage/v5/remove-overloads/utils/unknown-usage-error.js.html +1 -1
  28. package/build/codemods/coverage/v5/rename-hydrate/index.html +1 -1
  29. package/build/codemods/coverage/v5/rename-hydrate/rename-hydrate.js.html +1 -1
  30. package/build/codemods/coverage/v5/rename-properties/index.html +1 -1
  31. package/build/codemods/coverage/v5/rename-properties/rename-properties.js.html +1 -1
  32. package/build/legacy/useQueries.cjs.map +1 -1
  33. package/build/legacy/useQueries.d.cts +5 -5
  34. package/build/legacy/useQueries.d.ts +5 -5
  35. package/build/legacy/useQueries.js.map +1 -1
  36. package/build/legacy/useSuspenseQueries.cjs.map +1 -1
  37. package/build/legacy/useSuspenseQueries.d.cts +3 -3
  38. package/build/legacy/useSuspenseQueries.d.ts +3 -3
  39. package/build/legacy/useSuspenseQueries.js.map +1 -1
  40. package/build/legacy/useSuspenseQuery.cjs +5 -0
  41. package/build/legacy/useSuspenseQuery.cjs.map +1 -1
  42. package/build/legacy/useSuspenseQuery.js +6 -1
  43. package/build/legacy/useSuspenseQuery.js.map +1 -1
  44. package/build/modern/useQueries.cjs.map +1 -1
  45. package/build/modern/useQueries.d.cts +5 -5
  46. package/build/modern/useQueries.d.ts +5 -5
  47. package/build/modern/useQueries.js.map +1 -1
  48. package/build/modern/useSuspenseQueries.cjs.map +1 -1
  49. package/build/modern/useSuspenseQueries.d.cts +3 -3
  50. package/build/modern/useSuspenseQueries.d.ts +3 -3
  51. package/build/modern/useSuspenseQueries.js.map +1 -1
  52. package/build/modern/useSuspenseQuery.cjs +5 -0
  53. package/build/modern/useSuspenseQuery.cjs.map +1 -1
  54. package/build/modern/useSuspenseQuery.js +6 -1
  55. package/build/modern/useSuspenseQuery.js.map +1 -1
  56. package/build/query-codemods/vite.config.ts +1 -0
  57. package/package.json +2 -2
  58. package/src/__tests__/infiniteQueryOptions.test-d.tsx +4 -10
  59. package/src/__tests__/queryOptions.test-d.tsx +24 -2
  60. package/src/__tests__/suspense.test-d.tsx +11 -0
  61. package/src/__tests__/useInfiniteQuery.test.tsx +34 -58
  62. package/src/__tests__/useMutation.test.tsx +43 -62
  63. package/src/__tests__/useQueries.test.tsx +106 -104
  64. package/src/__tests__/useQuery.test.tsx +97 -47
  65. package/src/__tests__/utils.tsx +3 -10
  66. package/src/useQueries.ts +11 -7
  67. package/src/useSuspenseQueries.ts +7 -5
  68. package/src/useSuspenseQuery.ts +7 -1
@@ -2,6 +2,7 @@ import { describe, expect, expectTypeOf, it, test, vi } from 'vitest'
2
2
  import { act, fireEvent, render, waitFor } from '@testing-library/react'
3
3
  import * as React from 'react'
4
4
  import { ErrorBoundary } from 'react-error-boundary'
5
+ import { skipToken } from '@tanstack/query-core'
5
6
  import { QueryCache, keepPreviousData, useQuery } from '..'
6
7
  import {
7
8
  Blink,
@@ -32,29 +33,29 @@ describe('useQuery', () => {
32
33
  function Page() {
33
34
  // unspecified query function should default to unknown
34
35
  const noQueryFn = useQuery({ queryKey: key })
35
- expectTypeOf<unknown>(noQueryFn.data)
36
- expectTypeOf<unknown>(noQueryFn.error)
36
+ expectTypeOf(noQueryFn.data).toEqualTypeOf<unknown>()
37
+ expectTypeOf(noQueryFn.error).toEqualTypeOf<Error | null>()
37
38
 
38
39
  // it should infer the result type from the query function
39
40
  const fromQueryFn = useQuery({ queryKey: key, queryFn: () => 'test' })
40
- expectTypeOf<string | undefined>(fromQueryFn.data)
41
- expectTypeOf<unknown>(fromQueryFn.error)
41
+ expectTypeOf(fromQueryFn.data).toEqualTypeOf<string | undefined>()
42
+ expectTypeOf(fromQueryFn.error).toEqualTypeOf<Error | null>()
42
43
 
43
44
  // it should be possible to specify the result type
44
45
  const withResult = useQuery<string>({
45
46
  queryKey: key,
46
47
  queryFn: () => 'test',
47
48
  })
48
- expectTypeOf<string | undefined>(withResult.data)
49
- expectTypeOf<unknown | null>(withResult.error)
49
+ expectTypeOf(withResult.data).toEqualTypeOf<string | undefined>()
50
+ expectTypeOf(withResult.error).toEqualTypeOf<Error | null>()
50
51
 
51
52
  // it should be possible to specify the error type
52
53
  const withError = useQuery<string, Error>({
53
54
  queryKey: key,
54
55
  queryFn: () => 'test',
55
56
  })
56
- expectTypeOf<string | undefined>(withError.data)
57
- expectTypeOf<Error | null>(withError.error)
57
+ expectTypeOf(withError.data).toEqualTypeOf<string | undefined>()
58
+ expectTypeOf(withError.error).toEqualTypeOf<Error | null>()
58
59
 
59
60
  // it should provide the result type in the configuration
60
61
  useQuery({
@@ -65,14 +66,14 @@ describe('useQuery', () => {
65
66
  // it should be possible to specify a union type as result type
66
67
  const unionTypeSync = useQuery({
67
68
  queryKey: key,
68
- queryFn: () => (Math.random() > 0.5 ? 'a' : 'b'),
69
+ queryFn: () => (Math.random() > 0.5 ? ('a' as const) : ('b' as const)),
69
70
  })
70
- expectTypeOf<'a' | 'b' | undefined>(unionTypeSync.data)
71
+ expectTypeOf(unionTypeSync.data).toEqualTypeOf<'a' | 'b' | undefined>()
71
72
  const unionTypeAsync = useQuery<'a' | 'b'>({
72
73
  queryKey: key,
73
74
  queryFn: () => Promise.resolve(Math.random() > 0.5 ? 'a' : 'b'),
74
75
  })
75
- expectTypeOf<'a' | 'b' | undefined>(unionTypeAsync.data)
76
+ expectTypeOf(unionTypeAsync.data).toEqualTypeOf<'a' | 'b' | undefined>()
76
77
 
77
78
  // should error when the query function result does not match with the specified type
78
79
  // @ts-expect-error
@@ -87,15 +88,19 @@ describe('useQuery', () => {
87
88
  queryKey: key,
88
89
  queryFn: () => queryFn(),
89
90
  })
90
- expectTypeOf<string | undefined>(fromGenericQueryFn.data)
91
- expectTypeOf<unknown>(fromGenericQueryFn.error)
91
+ expectTypeOf(fromGenericQueryFn.data).toEqualTypeOf<string | undefined>()
92
+ expectTypeOf(fromGenericQueryFn.error).toEqualTypeOf<Error | null>()
92
93
 
93
94
  const fromGenericOptionsQueryFn = useQuery({
94
95
  queryKey: key,
95
96
  queryFn: () => queryFn(),
96
97
  })
97
- expectTypeOf<string | undefined>(fromGenericOptionsQueryFn.data)
98
- expectTypeOf<unknown>(fromGenericOptionsQueryFn.error)
98
+ expectTypeOf(fromGenericOptionsQueryFn.data).toEqualTypeOf<
99
+ string | undefined
100
+ >()
101
+ expectTypeOf(
102
+ fromGenericOptionsQueryFn.error,
103
+ ).toEqualTypeOf<Error | null>()
99
104
 
100
105
  type MyData = number
101
106
  type MyQueryKey = readonly ['my-data', number]
@@ -114,7 +119,7 @@ describe('useQuery', () => {
114
119
  const getMyDataStringKey: QueryFunction<MyData, ['1']> = async (
115
120
  context,
116
121
  ) => {
117
- expectTypeOf<['1']>(context.queryKey)
122
+ expectTypeOf(context.queryKey).toEqualTypeOf<['1']>()
118
123
  return Number(context.queryKey[0]) + 42
119
124
  }
120
125
 
@@ -153,7 +158,7 @@ describe('useQuery', () => {
153
158
  ...options,
154
159
  })
155
160
  const testQuery = useWrappedQuery([''], async () => '1')
156
- expectTypeOf<string | undefined>(testQuery.data)
161
+ expectTypeOf(testQuery.data).toEqualTypeOf<string | undefined>()
157
162
 
158
163
  // handles wrapped queries with custom fetcher passed directly to useQuery
159
164
  const useWrappedFuncStyleQuery = <
@@ -170,7 +175,7 @@ describe('useQuery', () => {
170
175
  >,
171
176
  ) => useQuery({ queryKey: qk, queryFn: fetcher, ...options })
172
177
  const testFuncStyle = useWrappedFuncStyleQuery([''], async () => true)
173
- expectTypeOf<boolean | undefined>(testFuncStyle.data)
178
+ expectTypeOf(testFuncStyle.data).toEqualTypeOf<boolean | undefined>()
174
179
  }
175
180
  })
176
181
 
@@ -217,19 +222,19 @@ describe('useQuery', () => {
217
222
  states.push(state)
218
223
 
219
224
  if (state.isPending) {
220
- expectTypeOf<undefined>(state.data)
221
- expectTypeOf<null>(state.error)
225
+ expectTypeOf(state.data).toEqualTypeOf<undefined>()
226
+ expectTypeOf(state.error).toEqualTypeOf<null>()
222
227
  return <span>pending</span>
223
228
  }
224
229
 
225
230
  if (state.isLoadingError) {
226
- expectTypeOf<undefined>(state.data)
227
- expectTypeOf<Error>(state.error)
231
+ expectTypeOf(state.data).toEqualTypeOf<undefined>()
232
+ expectTypeOf(state.error).toEqualTypeOf<Error>()
228
233
  return <span>{state.error.message}</span>
229
234
  }
230
235
 
231
- expectTypeOf<string>(state.data)
232
- expectTypeOf<Error | null>(state.error)
236
+ expectTypeOf(state.data).toEqualTypeOf<string>()
237
+ expectTypeOf(state.error).toEqualTypeOf<Error | null>()
233
238
  return <span>{state.data}</span>
234
239
  }
235
240
 
@@ -5211,12 +5216,11 @@ describe('useQuery', () => {
5211
5216
  }
5212
5217
 
5213
5218
  const rendered = renderWithClient(queryClient, <Page />)
5214
- window.dispatchEvent(new Event('offline'))
5215
5219
 
5216
5220
  await waitFor(() => rendered.getByText('status: pending, isPaused: true'))
5217
5221
 
5218
- onlineMock.mockRestore()
5219
- window.dispatchEvent(new Event('online'))
5222
+ onlineMock.mockReturnValue(true)
5223
+ queryClient.getQueryCache().onOnline()
5220
5224
 
5221
5225
  await waitFor(() =>
5222
5226
  rendered.getByText('status: success, isPaused: false'),
@@ -5226,6 +5230,7 @@ describe('useQuery', () => {
5226
5230
  })
5227
5231
 
5228
5232
  expect(states).toEqual(['paused', 'fetching', 'idle'])
5233
+ onlineMock.mockRestore()
5229
5234
  })
5230
5235
 
5231
5236
  it('online queries should not refetch if you are offline', async () => {
@@ -5264,7 +5269,6 @@ describe('useQuery', () => {
5264
5269
  await waitFor(() => rendered.getByText('data: data1'))
5265
5270
 
5266
5271
  const onlineMock = mockOnlineManagerIsOnline(false)
5267
- window.dispatchEvent(new Event('offline'))
5268
5272
 
5269
5273
  fireEvent.click(rendered.getByRole('button', { name: /invalidate/i }))
5270
5274
 
@@ -5275,8 +5279,8 @@ describe('useQuery', () => {
5275
5279
  )
5276
5280
  await waitFor(() => rendered.getByText('failureReason: null'))
5277
5281
 
5278
- onlineMock.mockRestore()
5279
- window.dispatchEvent(new Event('online'))
5282
+ onlineMock.mockReturnValue(true)
5283
+ queryClient.getQueryCache().onOnline()
5280
5284
 
5281
5285
  await waitFor(() =>
5282
5286
  rendered.getByText(
@@ -5294,6 +5298,8 @@ describe('useQuery', () => {
5294
5298
  await waitFor(() => {
5295
5299
  expect(rendered.getByText('data: data2')).toBeInTheDocument()
5296
5300
  })
5301
+
5302
+ onlineMock.mockRestore()
5297
5303
  })
5298
5304
 
5299
5305
  it('online queries should not refetch if you are offline and refocus', async () => {
@@ -5483,7 +5489,6 @@ describe('useQuery', () => {
5483
5489
  const onlineMock = mockOnlineManagerIsOnline(false)
5484
5490
 
5485
5491
  const rendered = renderWithClient(queryClient, <Page />)
5486
- window.dispatchEvent(new Event('offline'))
5487
5492
 
5488
5493
  await waitFor(() =>
5489
5494
  rendered.getByText('status: success, fetchStatus: paused'),
@@ -5506,10 +5511,8 @@ describe('useQuery', () => {
5506
5511
  window.dispatchEvent(new Event('visibilitychange'))
5507
5512
  })
5508
5513
 
5509
- onlineMock.mockRestore()
5510
- act(() => {
5511
- window.dispatchEvent(new Event('online'))
5512
- })
5514
+ onlineMock.mockReturnValue(true)
5515
+ queryClient.getQueryCache().onOnline()
5513
5516
 
5514
5517
  await waitFor(() =>
5515
5518
  rendered.getByText('status: success, fetchStatus: idle'),
@@ -5519,6 +5522,8 @@ describe('useQuery', () => {
5519
5522
  })
5520
5523
 
5521
5524
  expect(count).toBe(1)
5525
+
5526
+ onlineMock.mockRestore()
5522
5527
  })
5523
5528
 
5524
5529
  it('online queries should pause retries if you are offline', async () => {
@@ -5555,7 +5560,6 @@ describe('useQuery', () => {
5555
5560
  )
5556
5561
 
5557
5562
  const onlineMock = mockOnlineManagerIsOnline(false)
5558
- window.dispatchEvent(new Event('offline'))
5559
5563
 
5560
5564
  await sleep(20)
5561
5565
 
@@ -5569,7 +5573,7 @@ describe('useQuery', () => {
5569
5573
  expect(count).toBe(1)
5570
5574
 
5571
5575
  onlineMock.mockReturnValue(true)
5572
- window.dispatchEvent(new Event('online'))
5576
+ queryClient.getQueryCache().onOnline()
5573
5577
 
5574
5578
  await waitFor(() =>
5575
5579
  rendered.getByText('status: error, fetchStatus: idle, failureCount: 3'),
@@ -5620,16 +5624,14 @@ describe('useQuery', () => {
5620
5624
 
5621
5625
  const rendered = renderWithClient(queryClient, <Page />)
5622
5626
 
5623
- window.dispatchEvent(new Event('offline'))
5624
-
5625
5627
  await waitFor(() =>
5626
5628
  rendered.getByText('status: pending, fetchStatus: paused'),
5627
5629
  )
5628
5630
 
5629
5631
  fireEvent.click(rendered.getByRole('button', { name: /hide/i }))
5630
5632
 
5631
- onlineMock.mockRestore()
5632
- window.dispatchEvent(new Event('online'))
5633
+ onlineMock.mockReturnValue(true)
5634
+ queryClient.getQueryCache().onOnline()
5633
5635
 
5634
5636
  await waitFor(() => {
5635
5637
  expect(queryClient.getQueryState(key)).toMatchObject({
@@ -5641,6 +5643,8 @@ describe('useQuery', () => {
5641
5643
  // give it a bit more time to make sure queryFn is not called again
5642
5644
  await sleep(15)
5643
5645
  expect(count).toBe(1)
5646
+
5647
+ onlineMock.mockRestore()
5644
5648
  })
5645
5649
 
5646
5650
  it('online queries should not fetch if paused and we go online when cancelled and no refetchOnReconnect', async () => {
@@ -5690,7 +5694,7 @@ describe('useQuery', () => {
5690
5694
  expect(count).toBe(0)
5691
5695
 
5692
5696
  onlineMock.mockReturnValue(true)
5693
- window.dispatchEvent(new Event('online'))
5697
+ queryClient.getQueryCache().onOnline()
5694
5698
 
5695
5699
  await sleep(15)
5696
5700
 
@@ -5762,7 +5766,7 @@ describe('useQuery', () => {
5762
5766
  await sleep(15)
5763
5767
 
5764
5768
  onlineMock.mockReturnValue(true)
5765
- window.dispatchEvent(new Event('online'))
5769
+ queryClient.getQueryCache().onOnline()
5766
5770
 
5767
5771
  await sleep(15)
5768
5772
 
@@ -5896,8 +5900,6 @@ describe('useQuery', () => {
5896
5900
 
5897
5901
  const rendered = renderWithClient(queryClient, <Page />)
5898
5902
 
5899
- window.dispatchEvent(new Event('offline'))
5900
-
5901
5903
  await waitFor(() =>
5902
5904
  rendered.getByText(
5903
5905
  'status: pending, fetchStatus: paused, failureCount: 1',
@@ -5907,8 +5909,8 @@ describe('useQuery', () => {
5907
5909
 
5908
5910
  expect(count).toBe(1)
5909
5911
 
5910
- onlineMock.mockRestore()
5911
- window.dispatchEvent(new Event('online'))
5912
+ onlineMock.mockReturnValue(true)
5913
+ queryClient.getQueryCache().onOnline()
5912
5914
 
5913
5915
  await waitFor(() =>
5914
5916
  rendered.getByText('status: error, fetchStatus: idle, failureCount: 3'),
@@ -5916,6 +5918,7 @@ describe('useQuery', () => {
5916
5918
  await waitFor(() => rendered.getByText('failureReason: failed3'))
5917
5919
 
5918
5920
  expect(count).toBe(3)
5921
+ onlineMock.mockRestore()
5919
5922
  })
5920
5923
  })
5921
5924
 
@@ -6329,4 +6332,51 @@ describe('useQuery', () => {
6329
6332
  expect(() => render(<Page />)).toThrow('Bad argument type')
6330
6333
  consoleMock.mockRestore()
6331
6334
  })
6335
+
6336
+ it('should respect skipToken and refetch when skipToken is taken away', async () => {
6337
+ const key = queryKey()
6338
+
6339
+ function Page({ enabled }: { enabled: boolean }) {
6340
+ const { data, status } = useQuery({
6341
+ queryKey: [key],
6342
+ queryFn: enabled
6343
+ ? async () => {
6344
+ await sleep(10)
6345
+
6346
+ return Promise.resolve('data')
6347
+ }
6348
+ : skipToken,
6349
+ retry: false,
6350
+ retryOnMount: false,
6351
+ refetchOnMount: false,
6352
+ refetchOnWindowFocus: false,
6353
+ })
6354
+
6355
+ return (
6356
+ <div>
6357
+ <div>status: {status}</div>
6358
+ <div>data: {String(data)}</div>
6359
+ </div>
6360
+ )
6361
+ }
6362
+
6363
+ function App() {
6364
+ const [enabled, toggle] = React.useReducer((x) => !x, false)
6365
+
6366
+ return (
6367
+ <div>
6368
+ <Page enabled={enabled} />
6369
+ <button onClick={toggle}>enable</button>
6370
+ </div>
6371
+ )
6372
+ }
6373
+
6374
+ const rendered = renderWithClient(queryClient, <App />)
6375
+
6376
+ await waitFor(() => rendered.getByText('status: pending'))
6377
+
6378
+ fireEvent.click(rendered.getByRole('button', { name: 'enable' }))
6379
+ await waitFor(() => rendered.getByText('status: success'))
6380
+ await waitFor(() => rendered.getByText('data: data'))
6381
+ })
6332
6382
  })
@@ -4,7 +4,7 @@ import { act, render } from '@testing-library/react'
4
4
  import * as utils from '@tanstack/query-core'
5
5
  import { QueryClient, QueryClientProvider, onlineManager } from '..'
6
6
  import type { QueryClientConfig } from '..'
7
- import type { SpyInstance } from 'vitest'
7
+ import type { MockInstance } from 'vitest'
8
8
 
9
9
  export function renderWithClient(
10
10
  client: QueryClient,
@@ -48,13 +48,13 @@ export function createQueryClient(config?: QueryClientConfig): QueryClient {
48
48
 
49
49
  export function mockVisibilityState(
50
50
  value: DocumentVisibilityState,
51
- ): SpyInstance<[], DocumentVisibilityState> {
51
+ ): MockInstance<[], DocumentVisibilityState> {
52
52
  return vi.spyOn(document, 'visibilityState', 'get').mockReturnValue(value)
53
53
  }
54
54
 
55
55
  export function mockOnlineManagerIsOnline(
56
56
  value: boolean,
57
- ): SpyInstance<[], boolean> {
57
+ ): MockInstance<[], boolean> {
58
58
  return vi.spyOn(onlineManager, 'isOnline').mockReturnValue(value)
59
59
  }
60
60
 
@@ -78,13 +78,6 @@ export function setActTimeout(fn: () => void, ms?: number) {
78
78
  }, ms)
79
79
  }
80
80
 
81
- /**
82
- * Assert the parameter is not typed as `any`
83
- */
84
- export function expectTypeNotAny<T>(_: 0 extends 1 & T ? never : T): void {
85
- return undefined
86
- }
87
-
88
81
  // This monkey-patches the isServer-value from utils,
89
82
  // so that we can pretend to be in a server environment
90
83
  export function setIsServer(isServer: boolean) {
package/src/useQueries.ts CHANGED
@@ -32,6 +32,7 @@ import type {
32
32
  QueryClient,
33
33
  QueryFunction,
34
34
  QueryKey,
35
+ SkipToken,
35
36
  ThrowOnError,
36
37
  } from '@tanstack/query-core'
37
38
 
@@ -73,7 +74,9 @@ type GetOptions<T> =
73
74
  ? UseQueryOptionsForUseQueries<TQueryFnData>
74
75
  : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided
75
76
  T extends {
76
- queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
77
+ queryFn?:
78
+ | QueryFunction<infer TQueryFnData, infer TQueryKey>
79
+ | SkipToken
77
80
  select?: (data: any) => infer TData
78
81
  throwOnError?: ThrowOnError<any, infer TError, any, any>
79
82
  }
@@ -84,10 +87,9 @@ type GetOptions<T> =
84
87
  TQueryKey
85
88
  >
86
89
  : T extends {
87
- queryFn?: QueryFunction<
88
- infer TQueryFnData,
89
- infer TQueryKey
90
- >
90
+ queryFn?:
91
+ | QueryFunction<infer TQueryFnData, infer TQueryKey>
92
+ | SkipToken
91
93
  throwOnError?: ThrowOnError<any, infer TError, any, any>
92
94
  }
93
95
  ? UseQueryOptionsForUseQueries<
@@ -133,7 +135,7 @@ type GetResults<T> =
133
135
  ? GetDefinedOrUndefinedQueryResult<T, TQueryFnData>
134
136
  : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
135
137
  T extends {
136
- queryFn?: QueryFunction<infer TQueryFnData, any>
138
+ queryFn?: QueryFunction<infer TQueryFnData, any> | SkipToken
137
139
  select?: (data: any) => infer TData
138
140
  throwOnError?: ThrowOnError<any, infer TError, any, any>
139
141
  }
@@ -143,7 +145,9 @@ type GetResults<T> =
143
145
  unknown extends TError ? DefaultError : TError
144
146
  >
145
147
  : T extends {
146
- queryFn?: QueryFunction<infer TQueryFnData, any>
148
+ queryFn?:
149
+ | QueryFunction<infer TQueryFnData, any>
150
+ | SkipToken
147
151
  throwOnError?: ThrowOnError<any, infer TError, any, any>
148
152
  }
149
153
  ? GetDefinedOrUndefinedQueryResult<
@@ -6,6 +6,7 @@ import type {
6
6
  DefaultError,
7
7
  QueryClient,
8
8
  QueryFunction,
9
+ SkipToken,
9
10
  ThrowOnError,
10
11
  } from '@tanstack/query-core'
11
12
 
@@ -33,7 +34,9 @@ type GetSuspenseOptions<T> =
33
34
  ? UseSuspenseQueryOptions<TQueryFnData>
34
35
  : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided
35
36
  T extends {
36
- queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
37
+ queryFn?:
38
+ | QueryFunction<infer TQueryFnData, infer TQueryKey>
39
+ | SkipToken
37
40
  select?: (data: any) => infer TData
38
41
  throwOnError?: ThrowOnError<any, infer TError, any, any>
39
42
  }
@@ -44,10 +47,9 @@ type GetSuspenseOptions<T> =
44
47
  TQueryKey
45
48
  >
46
49
  : T extends {
47
- queryFn?: QueryFunction<
48
- infer TQueryFnData,
49
- infer TQueryKey
50
- >
50
+ queryFn?:
51
+ | QueryFunction<infer TQueryFnData, infer TQueryKey>
52
+ | SkipToken
51
53
  throwOnError?: ThrowOnError<any, infer TError, any, any>
52
54
  }
53
55
  ? UseSuspenseQueryOptions<
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- import { QueryObserver } from '@tanstack/query-core'
2
+ import { QueryObserver, skipToken } from '@tanstack/query-core'
3
3
  import { useBaseQuery } from './useBaseQuery'
4
4
  import { defaultThrowOnError } from './suspense'
5
5
  import type { UseSuspenseQueryOptions, UseSuspenseQueryResult } from './types'
@@ -14,6 +14,12 @@ export function useSuspenseQuery<
14
14
  options: UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
15
15
  queryClient?: QueryClient,
16
16
  ): UseSuspenseQueryResult<TData, TError> {
17
+ if (process.env.NODE_ENV !== 'production') {
18
+ if (options.queryFn === skipToken) {
19
+ console.error('skipToken is not allowed for useSuspenseQuery')
20
+ }
21
+ }
22
+
17
23
  return useBaseQuery(
18
24
  {
19
25
  ...options,