@suspensive/react-query-4 0.0.1-beta.0

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 (96) hide show
  1. package/LICENSE +21 -0
  2. package/dist/OmitKeyof-CFsZLI4k.d.cts +3 -0
  3. package/dist/OmitKeyof-CFsZLI4k.d.ts +3 -0
  4. package/dist/QueryErrorBoundary.cjs +81 -0
  5. package/dist/QueryErrorBoundary.cjs.map +1 -0
  6. package/dist/QueryErrorBoundary.d.cts +29 -0
  7. package/dist/QueryErrorBoundary.d.ts +29 -0
  8. package/dist/QueryErrorBoundary.js +9 -0
  9. package/dist/QueryErrorBoundary.js.map +1 -0
  10. package/dist/SuspenseInfiniteQuery.cjs +81 -0
  11. package/dist/SuspenseInfiniteQuery.cjs.map +1 -0
  12. package/dist/SuspenseInfiniteQuery.d.cts +14 -0
  13. package/dist/SuspenseInfiniteQuery.d.ts +14 -0
  14. package/dist/SuspenseInfiniteQuery.js +10 -0
  15. package/dist/SuspenseInfiniteQuery.js.map +1 -0
  16. package/dist/SuspenseQueries.cjs +69 -0
  17. package/dist/SuspenseQueries.cjs.map +1 -0
  18. package/dist/SuspenseQueries.d.cts +16 -0
  19. package/dist/SuspenseQueries.d.ts +16 -0
  20. package/dist/SuspenseQueries.js +10 -0
  21. package/dist/SuspenseQueries.js.map +1 -0
  22. package/dist/SuspenseQuery.cjs +81 -0
  23. package/dist/SuspenseQuery.cjs.map +1 -0
  24. package/dist/SuspenseQuery.d.cts +14 -0
  25. package/dist/SuspenseQuery.d.ts +14 -0
  26. package/dist/SuspenseQuery.js +10 -0
  27. package/dist/SuspenseQuery.js.map +1 -0
  28. package/dist/chunk-3B63MBHY.js +22 -0
  29. package/dist/chunk-3B63MBHY.js.map +1 -0
  30. package/dist/chunk-BN22WZP6.js +18 -0
  31. package/dist/chunk-BN22WZP6.js.map +1 -0
  32. package/dist/chunk-J3EHCRU6.js +20 -0
  33. package/dist/chunk-J3EHCRU6.js.map +1 -0
  34. package/dist/chunk-MEYWTEWA.js +11 -0
  35. package/dist/chunk-MEYWTEWA.js.map +1 -0
  36. package/dist/chunk-P5MROV72.js +34 -0
  37. package/dist/chunk-P5MROV72.js.map +1 -0
  38. package/dist/chunk-QETBZSG5.js +39 -0
  39. package/dist/chunk-QETBZSG5.js.map +1 -0
  40. package/dist/chunk-S7L2LUVS.js +22 -0
  41. package/dist/chunk-S7L2LUVS.js.map +1 -0
  42. package/dist/chunk-VPKMZV3T.js +23 -0
  43. package/dist/chunk-VPKMZV3T.js.map +1 -0
  44. package/dist/chunk-ZAOCTI7U.js +23 -0
  45. package/dist/chunk-ZAOCTI7U.js.map +1 -0
  46. package/dist/index.cjs +165 -0
  47. package/dist/index.cjs.map +1 -0
  48. package/dist/index.d.cts +13 -0
  49. package/dist/index.d.ts +13 -0
  50. package/dist/index.js +37 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/queryOptions.cjs +34 -0
  53. package/dist/queryOptions.cjs.map +1 -0
  54. package/dist/queryOptions.d.cts +17 -0
  55. package/dist/queryOptions.d.ts +17 -0
  56. package/dist/queryOptions.js +9 -0
  57. package/dist/queryOptions.js.map +1 -0
  58. package/dist/useSuspenseInfiniteQuery.cjs +56 -0
  59. package/dist/useSuspenseInfiniteQuery.cjs.map +1 -0
  60. package/dist/useSuspenseInfiniteQuery.d.cts +16 -0
  61. package/dist/useSuspenseInfiniteQuery.d.ts +16 -0
  62. package/dist/useSuspenseInfiniteQuery.js +9 -0
  63. package/dist/useSuspenseInfiniteQuery.js.map +1 -0
  64. package/dist/useSuspenseQueries.cjs +58 -0
  65. package/dist/useSuspenseQueries.cjs.map +1 -0
  66. package/dist/useSuspenseQueries.d.cts +55 -0
  67. package/dist/useSuspenseQueries.d.ts +55 -0
  68. package/dist/useSuspenseQueries.js +9 -0
  69. package/dist/useSuspenseQueries.js.map +1 -0
  70. package/dist/useSuspenseQuery.cjs +56 -0
  71. package/dist/useSuspenseQuery.cjs.map +1 -0
  72. package/dist/useSuspenseQuery.d.cts +16 -0
  73. package/dist/useSuspenseQuery.d.ts +16 -0
  74. package/dist/useSuspenseQuery.js +9 -0
  75. package/dist/useSuspenseQuery.js.map +1 -0
  76. package/package.json +80 -0
  77. package/src/QueryErrorBoundary.tsx +27 -0
  78. package/src/SuspenseInfiniteQuery.test-d.tsx +102 -0
  79. package/src/SuspenseInfiniteQuery.tsx +22 -0
  80. package/src/SuspenseQueries.test-d.tsx +54 -0
  81. package/src/SuspenseQueries.tsx +15 -0
  82. package/src/SuspenseQuery.test-d.tsx +94 -0
  83. package/src/SuspenseQuery.tsx +18 -0
  84. package/src/index.ts +13 -0
  85. package/src/queryOptions.test-d.tsx +119 -0
  86. package/src/queryOptions.ts +88 -0
  87. package/src/useSuspenseInfiniteQuery.test-d.ts +59 -0
  88. package/src/useSuspenseInfiniteQuery.ts +47 -0
  89. package/src/useSuspenseQueries.test-d.ts +75 -0
  90. package/src/useSuspenseQueries.ts +127 -0
  91. package/src/useSuspenseQuery.test-d.ts +51 -0
  92. package/src/useSuspenseQuery.ts +36 -0
  93. package/src/utility-types/OmitKeyof.test-d.ts +175 -0
  94. package/src/utility-types/OmitKeyof.ts +11 -0
  95. package/src/utility-types/RequiredKeyof.ts +3 -0
  96. package/src/utility-types/index.ts +2 -0
@@ -0,0 +1,22 @@
1
+ import type { QueryKey } from '@tanstack/react-query'
2
+ import type { ReactNode } from 'react'
3
+ import {
4
+ type UseSuspenseInfiniteQueryOptions,
5
+ type UseSuspenseInfiniteQueryResult,
6
+ useSuspenseInfiniteQuery,
7
+ } from './useSuspenseInfiniteQuery'
8
+
9
+ /**
10
+ * @experimental This is experimental feature.
11
+ */
12
+ export const SuspenseInfiniteQuery = <
13
+ TQueryFnData = unknown,
14
+ TError = unknown,
15
+ TData = TQueryFnData,
16
+ TQueryKey extends QueryKey = QueryKey,
17
+ >({
18
+ children,
19
+ ...options
20
+ }: UseSuspenseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
21
+ children: (query: UseSuspenseInfiniteQueryResult<TData, TError>) => ReactNode
22
+ }) => <>{children(useSuspenseInfiniteQuery(options))}</>
@@ -0,0 +1,54 @@
1
+ import { queryFn, queryKey } from '@suspensive/test-utils'
2
+ import type { ReactNode } from 'react'
3
+ import { describe, expectTypeOf, it } from 'vitest'
4
+ import { SuspenseQueries } from './SuspenseQueries'
5
+ import type { UseSuspenseQueryResult } from './useSuspenseQuery'
6
+
7
+ describe('<SuspenseQueries/>', () => {
8
+ it('type check', () => {
9
+ ;() => (
10
+ <SuspenseQueries queries={[{ queryKey, queryFn }]}>
11
+ {([
12
+ query1,
13
+ // @ts-expect-error Tuple type '[UseSuspenseQueryResult<{ text: string; }, unknown>]' of length '1' has no element at index '1'.
14
+ query2,
15
+ // @ts-expect-error Tuple type '[UseSuspenseQueryResult<{ text: string; }, unknown>]' of length '1' has no element at index '2'.
16
+ query3,
17
+ ]) => {
18
+ expectTypeOf(query1).toEqualTypeOf<UseSuspenseQueryResult<{ text: string }>>()
19
+ expectTypeOf(query2).toEqualTypeOf<undefined>()
20
+ expectTypeOf(query3).toEqualTypeOf<undefined>()
21
+ return <></>
22
+ }}
23
+ </SuspenseQueries>
24
+ )
25
+ ;() => (
26
+ <SuspenseQueries
27
+ queries={[
28
+ { queryKey, queryFn },
29
+ { queryKey, queryFn },
30
+ ]}
31
+ >
32
+ {([
33
+ query1,
34
+
35
+ query2,
36
+ // @ts-expect-error Tuple type '[UseSuspenseQueryResult<{ text: string; }, unknown>]' of length '1' has no element at index '2'.
37
+ query3,
38
+ ]) => {
39
+ expectTypeOf(query1).toEqualTypeOf<UseSuspenseQueryResult<{ text: string }>>()
40
+ expectTypeOf(query2).toEqualTypeOf<UseSuspenseQueryResult<{ text: string }>>()
41
+ expectTypeOf(query3).toEqualTypeOf<undefined>()
42
+ return <></>
43
+ }}
44
+ </SuspenseQueries>
45
+ )
46
+
47
+ expectTypeOf(
48
+ <SuspenseQueries queries={[{ queryKey, queryFn }]}>{() => <></>}</SuspenseQueries>
49
+ ).toEqualTypeOf<JSX.Element>()
50
+ expectTypeOf(
51
+ <SuspenseQueries queries={[{ queryKey, queryFn }]}>{() => <></>}</SuspenseQueries>
52
+ ).not.toEqualTypeOf<ReactNode>()
53
+ })
54
+ })
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react'
2
+ import { type SuspenseQueriesOptions, type SuspenseQueriesResults, useSuspenseQueries } from './useSuspenseQueries'
3
+
4
+ /**
5
+ * @experimental This is experimental feature.
6
+ */
7
+ export function SuspenseQueries<T extends any[]>({
8
+ children,
9
+ queries,
10
+ }: {
11
+ queries: readonly [...SuspenseQueriesOptions<T>]
12
+ children: (queries: SuspenseQueriesResults<T>) => ReactNode
13
+ }) {
14
+ return <>{children(useSuspenseQueries({ queries }))}</>
15
+ }
@@ -0,0 +1,94 @@
1
+ import { queryFn, queryKey } from '@suspensive/test-utils'
2
+ import type { ReactNode } from 'react'
3
+ import { describe, expectTypeOf, it } from 'vitest'
4
+ import { SuspenseQuery } from './SuspenseQuery'
5
+ import type { UseSuspenseQueryResult } from './useSuspenseQuery'
6
+
7
+ describe('<SuspenseQuery/>', () => {
8
+ it('type error', () => {
9
+ ;() => (
10
+ <SuspenseQuery
11
+ queryKey={queryKey}
12
+ queryFn={queryFn}
13
+ //@ts-expect-error no suspense
14
+ suspense={boolean}
15
+ >
16
+ {(query) => <>{query.data.text}</>}
17
+ </SuspenseQuery>
18
+ )
19
+ ;() => (
20
+ <SuspenseQuery
21
+ queryKey={queryKey}
22
+ queryFn={queryFn}
23
+ //@ts-expect-error no useErrorBoundary
24
+ useErrorBoundary={boolean}
25
+ >
26
+ {(query) => <>{query.data.text}</>}
27
+ </SuspenseQuery>
28
+ )
29
+ ;() => (
30
+ <SuspenseQuery
31
+ queryKey={queryKey}
32
+ queryFn={queryFn}
33
+ //@ts-expect-error no enabled
34
+ enabled={boolean}
35
+ >
36
+ {(query) => <>{query.data.text}</>}
37
+ </SuspenseQuery>
38
+ )
39
+ ;() => (
40
+ <SuspenseQuery
41
+ queryKey={queryKey}
42
+ queryFn={queryFn}
43
+ //@ts-expect-error no placeholderData
44
+ placeholderData="placeholder"
45
+ >
46
+ {(query) => <>{query.data.text}</>}
47
+ </SuspenseQuery>
48
+ )
49
+ ;() => (
50
+ <SuspenseQuery
51
+ queryKey={queryKey}
52
+ queryFn={queryFn}
53
+ //@ts-expect-error no placeholderData
54
+ placeholderData="placeholder"
55
+ >
56
+ {(query) => <>{query.data.text}</>}
57
+ </SuspenseQuery>
58
+ )
59
+ })
60
+
61
+ it('type check', () => {
62
+ ;() => (
63
+ <SuspenseQuery queryKey={queryKey} queryFn={queryFn}>
64
+ {(query) => {
65
+ expectTypeOf(query).toEqualTypeOf<UseSuspenseQueryResult<{ text: string }>>()
66
+ expectTypeOf(query.data).toEqualTypeOf<{ text: string }>()
67
+ expectTypeOf(query.status).toEqualTypeOf<'success'>()
68
+ return <></>
69
+ }}
70
+ </SuspenseQuery>
71
+ )
72
+ ;() => (
73
+ <SuspenseQuery queryKey={queryKey} queryFn={queryFn} select={(data) => data.text}>
74
+ {(selectedQuery) => {
75
+ expectTypeOf(selectedQuery).toEqualTypeOf<UseSuspenseQueryResult<string>>()
76
+ expectTypeOf(selectedQuery.data).toEqualTypeOf<string>()
77
+ expectTypeOf(selectedQuery.status).toEqualTypeOf<'success'>()
78
+ return <></>
79
+ }}
80
+ </SuspenseQuery>
81
+ )
82
+
83
+ expectTypeOf(
84
+ <SuspenseQuery queryKey={queryKey} queryFn={queryFn}>
85
+ {() => <></>}
86
+ </SuspenseQuery>
87
+ ).toEqualTypeOf<JSX.Element>()
88
+ expectTypeOf(
89
+ <SuspenseQuery queryKey={queryKey} queryFn={queryFn}>
90
+ {() => <></>}
91
+ </SuspenseQuery>
92
+ ).not.toEqualTypeOf<ReactNode>()
93
+ })
94
+ })
@@ -0,0 +1,18 @@
1
+ import type { QueryKey } from '@tanstack/react-query'
2
+ import type { ReactNode } from 'react'
3
+ import { type UseSuspenseQueryOptions, type UseSuspenseQueryResult, useSuspenseQuery } from './useSuspenseQuery'
4
+
5
+ /**
6
+ * @experimental This is experimental feature.
7
+ */
8
+ export const SuspenseQuery = <
9
+ TQueryFnData = unknown,
10
+ TError = unknown,
11
+ TData = TQueryFnData,
12
+ TQueryKey extends QueryKey = QueryKey,
13
+ >({
14
+ children,
15
+ ...options
16
+ }: UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
17
+ children: (queryResult: UseSuspenseQueryResult<TData, TError>) => ReactNode
18
+ }) => <>{children(useSuspenseQuery(options))}</>
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ export { queryOptions } from './queryOptions'
2
+ export { SuspenseQuery } from './SuspenseQuery'
3
+ export { SuspenseQueries } from './SuspenseQueries'
4
+ export { SuspenseInfiniteQuery } from './SuspenseInfiniteQuery'
5
+
6
+ export { useSuspenseQuery } from './useSuspenseQuery'
7
+ export type { UseSuspenseQueryOptions, UseSuspenseQueryResult } from './useSuspenseQuery'
8
+ export { useSuspenseQueries } from './useSuspenseQueries'
9
+ export type { SuspenseQueriesOptions, SuspenseQueriesResults } from './useSuspenseQueries'
10
+ export { useSuspenseInfiniteQuery } from './useSuspenseInfiniteQuery'
11
+ export type { UseSuspenseInfiniteQueryOptions, UseSuspenseInfiniteQueryResult } from './useSuspenseInfiniteQuery'
12
+
13
+ export { QueryErrorBoundary } from './QueryErrorBoundary'
@@ -0,0 +1,119 @@
1
+ import { queryKey } from '@suspensive/test-utils'
2
+ import { type UseQueryResult, useQueries, useQuery, useQueryClient } from '@tanstack/react-query'
3
+ import { describe, expectTypeOf, it } from 'vitest'
4
+ import { queryOptions } from './queryOptions'
5
+ import { SuspenseQuery } from './SuspenseQuery'
6
+ import { useSuspenseQueries } from './useSuspenseQueries'
7
+ import { type UseSuspenseQueryResult, useSuspenseQuery } from './useSuspenseQuery'
8
+
9
+ const query = {
10
+ options1: () =>
11
+ queryOptions({
12
+ queryKey: [...queryKey, 1] as const,
13
+ queryFn: () => Promise.resolve({ field: 'success' }),
14
+ }),
15
+ options2: () =>
16
+ queryOptions({
17
+ queryKey: [...queryKey, 2] as const,
18
+ queryFn: () => Promise.resolve({ field: 'success' }),
19
+ }),
20
+ }
21
+
22
+ describe('queryOptions', () => {
23
+ it('should be used with useQuery', () => {
24
+ const keyFn1Query = useQuery(query.options1())
25
+ expectTypeOf(keyFn1Query).toEqualTypeOf<UseQueryResult<{ field: string }>>()
26
+ expectTypeOf(keyFn1Query.data).toEqualTypeOf<{ field: string } | undefined>()
27
+ const keyFn1Query_Select = useQuery({ ...query.options1(), select: (data) => data.field })
28
+ expectTypeOf(keyFn1Query_Select).toEqualTypeOf<UseQueryResult<string>>()
29
+ expectTypeOf(keyFn1Query_Select.data).toEqualTypeOf<string | undefined>()
30
+ })
31
+ it('should be used with useSuspenseQuery', () => {
32
+ const keyFn1SuspenseQuery = useSuspenseQuery(query.options1())
33
+ expectTypeOf(keyFn1SuspenseQuery).toEqualTypeOf<UseSuspenseQueryResult<{ field: string }>>()
34
+ expectTypeOf(keyFn1SuspenseQuery.data).toEqualTypeOf<{ field: string }>()
35
+ const keyFn1SuspenseQuery_Select = useSuspenseQuery({ ...query.options1(), select: (data) => data.field })
36
+ expectTypeOf(keyFn1SuspenseQuery_Select).toEqualTypeOf<UseSuspenseQueryResult<string>>()
37
+ expectTypeOf(keyFn1SuspenseQuery_Select.data).toEqualTypeOf<string>()
38
+ })
39
+ it('should be used with <SuspenseQuery/>', () => {
40
+ ;(() => (
41
+ <SuspenseQuery {...query.options1()}>
42
+ {(keyFn1SuspenseQuery) => {
43
+ expectTypeOf(keyFn1SuspenseQuery).toEqualTypeOf<UseSuspenseQueryResult<{ field: string }>>()
44
+ expectTypeOf(keyFn1SuspenseQuery.data).toEqualTypeOf<{ field: string }>()
45
+ return <></>
46
+ }}
47
+ </SuspenseQuery>
48
+ ))()
49
+ ;(() => (
50
+ <SuspenseQuery {...query.options1()} select={(data) => data.field}>
51
+ {(keyFn1SuspenseQuery_Select) => {
52
+ expectTypeOf(keyFn1SuspenseQuery_Select).toEqualTypeOf<UseSuspenseQueryResult<string>>()
53
+ expectTypeOf(keyFn1SuspenseQuery_Select.data).toEqualTypeOf<string>()
54
+ return <></>
55
+ }}
56
+ </SuspenseQuery>
57
+ ))()
58
+ })
59
+
60
+ it('should be used with useQueries', () => {
61
+ const [query1, query2, query3] = useQueries({
62
+ queries: [
63
+ query.options1(),
64
+ { ...query.options2() },
65
+ queryOptions({
66
+ queryKey: [...queryKey, 4] as const,
67
+ queryFn: () => Promise.resolve({ field: 'success' }),
68
+ select: (data) => {
69
+ expectTypeOf(data).toEqualTypeOf<{ field: string }>()
70
+ return data.field
71
+ },
72
+ }),
73
+ ],
74
+ })
75
+ expectTypeOf(query1).toEqualTypeOf<UseQueryResult<{ field: string }>>()
76
+ expectTypeOf(query1.data).toEqualTypeOf<{ field: string } | undefined>()
77
+ expectTypeOf(query2).toEqualTypeOf<UseQueryResult<{ field: string }>>()
78
+ expectTypeOf(query2.data).toEqualTypeOf<{ field: string } | undefined>()
79
+ expectTypeOf(query3).toEqualTypeOf<UseQueryResult<string>>()
80
+ expectTypeOf(query3.data).toEqualTypeOf<string | undefined>()
81
+ })
82
+ it('should be used with useSuspenseQueries', () => {
83
+ const [query1, query2, query3] = useSuspenseQueries({
84
+ queries: [
85
+ query.options1(),
86
+ { ...query.options2() },
87
+ queryOptions({
88
+ queryKey: [...queryKey, 4] as const,
89
+ queryFn: () => Promise.resolve({ field: 'success' }),
90
+ select: (data) => {
91
+ expectTypeOf(data).toEqualTypeOf<{ field: string }>()
92
+ return data.field
93
+ },
94
+ }),
95
+ ],
96
+ })
97
+
98
+ expectTypeOf(query1).toEqualTypeOf<UseSuspenseQueryResult<{ field: string }>>()
99
+ expectTypeOf(query1.data).toEqualTypeOf<{ field: string }>()
100
+ expectTypeOf(query2).toEqualTypeOf<UseSuspenseQueryResult<{ field: string }>>()
101
+ expectTypeOf(query2.data).toEqualTypeOf<{ field: string }>()
102
+ expectTypeOf(query3).toEqualTypeOf<UseSuspenseQueryResult<string>>()
103
+ expectTypeOf(query3.data).toEqualTypeOf<string>()
104
+ })
105
+
106
+ it('should be used with useQueryClient', async () => {
107
+ const queryClient = useQueryClient()
108
+
109
+ queryClient.invalidateQueries(query.options1())
110
+ queryClient.resetQueries(query.options1())
111
+ queryClient.removeQueries(query.options1())
112
+ queryClient.cancelQueries(query.options1())
113
+ queryClient.prefetchQuery(query.options1())
114
+ queryClient.refetchQueries(query.options1())
115
+
116
+ const query1 = await queryClient.fetchQuery(query.options1())
117
+ expectTypeOf(query1).toEqualTypeOf<{ field: string }>()
118
+ })
119
+ })
@@ -0,0 +1,88 @@
1
+ import type { QueryKey, UseQueryOptions } from '@tanstack/react-query'
2
+ import type { OmitKeyof, RequiredKeyof } from './utility-types'
3
+
4
+ type SelectedQueryOptions<
5
+ TQueryFnData = unknown,
6
+ TError = unknown,
7
+ TData = TQueryFnData,
8
+ TQueryKey extends QueryKey = QueryKey,
9
+ > = RequiredKeyof<
10
+ OmitKeyof<
11
+ UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
12
+ | 'getNextPageParam'
13
+ | 'getPreviousPageParam'
14
+ | 'queryKeyHashFn'
15
+ | '_defaulted'
16
+ | 'behavior'
17
+ | 'structuralSharing'
18
+ | 'isDataEqual'
19
+ | 'onSuccess'
20
+ | 'onError'
21
+ | 'onSettled'
22
+ | 'enabled'
23
+ | 'refetchInterval'
24
+ | 'initialData'
25
+ >,
26
+ 'queryKey' | 'queryFn'
27
+ > & {
28
+ select: (data: TQueryFnData) => TData
29
+ }
30
+
31
+ type UnSelectedQueryOptions<
32
+ TQueryFnData = unknown,
33
+ TError = unknown,
34
+ TData = TQueryFnData,
35
+ TQueryKey extends QueryKey = QueryKey,
36
+ > = RequiredKeyof<
37
+ OmitKeyof<
38
+ UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
39
+ | 'getNextPageParam'
40
+ | 'getPreviousPageParam'
41
+ | 'queryKeyHashFn'
42
+ | '_defaulted'
43
+ | 'behavior'
44
+ | 'structuralSharing'
45
+ | 'isDataEqual'
46
+ | 'onSuccess'
47
+ | 'onError'
48
+ | 'onSettled'
49
+ | 'enabled'
50
+ | 'refetchInterval'
51
+ | 'initialData'
52
+ >,
53
+ 'queryKey' | 'queryFn'
54
+ > & {
55
+ select?: undefined
56
+ }
57
+
58
+ export function queryOptions<
59
+ TQueryFnData = unknown,
60
+ TError = unknown,
61
+ TData = TQueryFnData,
62
+ TQueryKey extends QueryKey = QueryKey,
63
+ >(
64
+ options: SelectedQueryOptions<TQueryFnData, TError, TData, TQueryKey>
65
+ ): SelectedQueryOptions<TQueryFnData, TError, TData, TQueryKey>
66
+ export function queryOptions<
67
+ TQueryFnData = unknown,
68
+ TError = unknown,
69
+ TData = TQueryFnData,
70
+ TQueryKey extends QueryKey = QueryKey,
71
+ >(
72
+ options: UnSelectedQueryOptions<TQueryFnData, TError, TData, TQueryKey>
73
+ ): UnSelectedQueryOptions<TQueryFnData, TError, TData, TQueryKey>
74
+ /**
75
+ * @experimental This is experimental feature.
76
+ */
77
+ export function queryOptions<
78
+ TQueryFnData = unknown,
79
+ TError = unknown,
80
+ TData = TQueryFnData,
81
+ TQueryKey extends QueryKey = QueryKey,
82
+ >(
83
+ options:
84
+ | SelectedQueryOptions<TQueryFnData, TError, TData, TQueryKey>
85
+ | UnSelectedQueryOptions<TQueryFnData, TError, TData, TQueryKey>
86
+ ) {
87
+ return options
88
+ }
@@ -0,0 +1,59 @@
1
+ import { queryFn, queryKey } from '@suspensive/test-utils'
2
+ import type { InfiniteData } from '@tanstack/react-query'
3
+ import { type UseSuspenseInfiniteQueryResult, useSuspenseInfiniteQuery } from './useSuspenseInfiniteQuery'
4
+
5
+ describe('useSuspenseInfiniteQuery', () => {
6
+ it('type error', () => {
7
+ // @ts-expect-error no arg
8
+ useSuspenseInfiniteQuery()
9
+
10
+ useSuspenseInfiniteQuery({
11
+ queryKey,
12
+ queryFn,
13
+ // @ts-expect-error no suspense
14
+ suspense: boolean,
15
+ })
16
+ useSuspenseInfiniteQuery({
17
+ queryKey,
18
+ queryFn,
19
+ // @ts-expect-error no useErrorBoundary
20
+ useErrorBoundary: boolean,
21
+ })
22
+ useSuspenseInfiniteQuery({
23
+ queryKey,
24
+ queryFn,
25
+ // @ts-expect-error no enabled
26
+ enabled: boolean,
27
+ })
28
+ useSuspenseInfiniteQuery({
29
+ queryKey,
30
+ queryFn,
31
+ // @ts-expect-error no placeholderData
32
+ placeholderData: 'placeholder',
33
+ })
34
+ useSuspenseInfiniteQuery({
35
+ queryKey,
36
+ queryFn,
37
+ // @ts-expect-error no isPlaceholderData
38
+ }).isPlaceholderData
39
+ })
40
+
41
+ it('type check', () => {
42
+ const infiniteQuery = useSuspenseInfiniteQuery({ queryKey, queryFn })
43
+ expectTypeOf(infiniteQuery).toEqualTypeOf<UseSuspenseInfiniteQueryResult<{ text: string }>>()
44
+ expectTypeOf(infiniteQuery.data).toEqualTypeOf<InfiniteData<{ text: string }>>()
45
+ expectTypeOf(infiniteQuery.status).toEqualTypeOf<'success'>()
46
+
47
+ const selectedInfiniteQuery = useSuspenseInfiniteQuery({
48
+ queryKey,
49
+ queryFn,
50
+ select: (data) => ({
51
+ pages: data.pages.map(({ text }) => text),
52
+ pageParams: data.pageParams,
53
+ }),
54
+ })
55
+ expectTypeOf(selectedInfiniteQuery).toEqualTypeOf<UseSuspenseInfiniteQueryResult<string>>()
56
+ expectTypeOf(selectedInfiniteQuery.data).toEqualTypeOf<InfiniteData<string>>()
57
+ expectTypeOf(selectedInfiniteQuery.status).toEqualTypeOf<'success'>()
58
+ })
59
+ })
@@ -0,0 +1,47 @@
1
+ import {
2
+ type InfiniteData,
3
+ type QueryKey,
4
+ type UseInfiniteQueryOptions,
5
+ type UseInfiniteQueryResult,
6
+ useInfiniteQuery,
7
+ } from '@tanstack/react-query'
8
+ import type { OmitKeyof } from './utility-types'
9
+
10
+ export interface UseSuspenseInfiniteQueryResult<TData = unknown, TError = unknown>
11
+ extends OmitKeyof<
12
+ UseInfiniteQueryResult<TData, TError>,
13
+ keyof Pick<UseInfiniteQueryResult<TData, TError>, 'isPlaceholderData'>
14
+ > {
15
+ data: InfiniteData<TData>
16
+ status: 'success'
17
+ }
18
+
19
+ export interface UseSuspenseInfiniteQueryOptions<
20
+ TQueryFnData = unknown,
21
+ TError = unknown,
22
+ TData = TQueryFnData,
23
+ TQueryKey extends QueryKey = QueryKey,
24
+ > extends OmitKeyof<
25
+ UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>,
26
+ 'suspense' | 'useErrorBoundary' | 'enabled' | 'placeholderData'
27
+ > {}
28
+
29
+ /**
30
+ * This hook is wrapping useInfiniteQuery of `@tanstack/react-query` v4 with default suspense option.
31
+ * @see {@link https://suspensive.org/docs/react-query/useSuspenseInfiniteQuery}
32
+ */
33
+ export function useSuspenseInfiniteQuery<
34
+ TQueryFnData = unknown,
35
+ TError = unknown,
36
+ TData = TQueryFnData,
37
+ TQueryKey extends QueryKey = QueryKey,
38
+ >(
39
+ options: UseSuspenseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
40
+ ): UseSuspenseInfiniteQueryResult<TData, TError> {
41
+ return useInfiniteQuery({
42
+ ...options,
43
+ enabled: true,
44
+ suspense: true,
45
+ useErrorBoundary: true,
46
+ }) as UseSuspenseInfiniteQueryResult<TData, TError>
47
+ }
@@ -0,0 +1,75 @@
1
+ import { queryFn, queryKey, select } from '@suspensive/test-utils'
2
+ import { describe, expectTypeOf, it } from 'vitest'
3
+ import { queryOptions } from './queryOptions'
4
+ import { useSuspenseQueries } from './useSuspenseQueries'
5
+ import type { UseSuspenseQueryResult } from './useSuspenseQuery'
6
+
7
+ describe('useSuspenseQueries', () => {
8
+ it('type error', () => {
9
+ useSuspenseQueries({
10
+ queries: [
11
+ {
12
+ queryKey: [...queryKey, 1] as const,
13
+ queryFn,
14
+ // @ts-expect-error no suspense
15
+ suspense: false,
16
+ },
17
+ {
18
+ queryKey: [...queryKey, 2] as const,
19
+ queryFn,
20
+ select,
21
+ // @ts-expect-error no suspense
22
+ suspense: true,
23
+ },
24
+ {
25
+ queryKey: [...queryKey, 3] as const,
26
+ queryFn,
27
+ // @ts-expect-error no enabled
28
+ enabled: true,
29
+ },
30
+ {
31
+ queryKey: [...queryKey, 4] as const,
32
+ queryFn,
33
+ // @ts-expect-error no enabled
34
+ enabled: true,
35
+ select,
36
+ },
37
+ queryOptions({
38
+ queryKey: [...queryKey, 4] as const,
39
+ queryFn: () => Promise.resolve({ field: 'success' }),
40
+ select: (data) => data.field,
41
+ }),
42
+ ] as const,
43
+ })
44
+ // @ts-expect-error if no items
45
+ useSuspenseQueries({})
46
+ // @ts-expect-error if no items
47
+ useSuspenseQueries()
48
+ })
49
+
50
+ it('type check', () => {
51
+ const [query, selectedQuery, selectedQueryByQueryOptions] = useSuspenseQueries({
52
+ queries: [
53
+ { queryKey: [...queryKey, 5] as const, queryFn },
54
+ { queryKey: [...queryKey, 6] as const, queryFn, select },
55
+ queryOptions({
56
+ queryKey: [...queryKey, 4] as const,
57
+ queryFn: () => Promise.resolve({ field: 'success' }),
58
+ select: (data) => data.field,
59
+ }),
60
+ ] as const,
61
+ })
62
+
63
+ expectTypeOf(query).toEqualTypeOf<UseSuspenseQueryResult<{ text: string }>>()
64
+ expectTypeOf(query.status).toEqualTypeOf<`success`>()
65
+ expectTypeOf(query.data).toEqualTypeOf<{ text: string }>()
66
+
67
+ expectTypeOf(selectedQuery).toEqualTypeOf<UseSuspenseQueryResult<string>>()
68
+ expectTypeOf(selectedQuery.status).toEqualTypeOf<`success`>()
69
+ expectTypeOf(selectedQuery.data).toEqualTypeOf<string>()
70
+
71
+ expectTypeOf(selectedQueryByQueryOptions).toEqualTypeOf<UseSuspenseQueryResult<string>>()
72
+ expectTypeOf(selectedQueryByQueryOptions.status).toEqualTypeOf<`success`>()
73
+ expectTypeOf(selectedQueryByQueryOptions.data).toEqualTypeOf<string>()
74
+ })
75
+ })