Skip to content

Commit 7f305ec

Browse files
authored
Merge branch 'main' into fix/no-void-query-fn-ts6-enum
2 parents 26d8141 + 608706e commit 7f305ec

48 files changed

Lines changed: 4198 additions & 132 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/framework/react/guides/advanced-ssr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ This ensures that only successfully resolved queries are persisted to storage, p
555555

556556
While we recommend the prefetching solution detailed above because it flattens request waterfalls both on the initial page load **and** any subsequent page navigation, there is an experimental way to skip prefetching altogether and still have streaming SSR work: `@tanstack/react-query-next-experimental`
557557

558-
This package will allow you to fetch data on the server (in a Client Component) by just calling `useSuspenseQuery` in your component. Results will then be streamed from the server to the client as SuspenseBoundaries resolve. If you call `useSuspenseQuery` without wrapping it in a `<Suspense>` boundary, the HTML response won't start until the fetch resolves. This can be when you want depending on the situation, but keep in mind that this will hurt your TTFB.
558+
This package will allow you to fetch data on the server (in a Client Component) by just calling `useSuspenseQuery` in your component. Results will then be streamed from the server to the client as SuspenseBoundaries resolve. If you call `useSuspenseQuery` without wrapping it in a `<Suspense>` boundary, the HTML response won't start until the fetch resolves. This can be what you want depending on the situation, but keep in mind that this will hurt your TTFB.
559559

560560
To achieve this, wrap your app in the `ReactQueryStreamedHydration` component:
561561

examples/preact/simple/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"preview": "vite preview"
99
},
1010
"dependencies": {
11-
"@tanstack/preact-query": "workspace:^",
11+
"@tanstack/preact-query": "^5.99.0",
1212
"preact": "^10.28.0"
1313
},
1414
"devDependencies": {
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { describe, expectTypeOf, it } from 'vitest'
2+
import { QueryClient } from '@tanstack/query-core'
3+
import { useMutation } from '../useMutation'
4+
import type { DefaultError } from '@tanstack/query-core'
5+
import type { UseMutationResult } from '../types'
6+
7+
describe('useMutation', () => {
8+
it('should infer TData from mutationFn return type', () => {
9+
const mutation = useMutation({
10+
mutationFn: () => Promise.resolve('data'),
11+
})
12+
13+
expectTypeOf(mutation.data).toEqualTypeOf<string | undefined>()
14+
expectTypeOf(mutation.error).toEqualTypeOf<DefaultError | null>()
15+
})
16+
17+
it('should infer TVariables from mutationFn parameter', () => {
18+
const mutation = useMutation({
19+
mutationFn: (vars: { id: string }) => Promise.resolve(vars.id),
20+
})
21+
22+
expectTypeOf(mutation.mutate).toBeCallableWith({ id: '1' })
23+
expectTypeOf(mutation.data).toEqualTypeOf<string | undefined>()
24+
})
25+
26+
it('should infer TOnMutateResult from onMutate return type', () => {
27+
useMutation({
28+
mutationFn: () => Promise.resolve('data'),
29+
onMutate: () => {
30+
return { token: 'abc' }
31+
},
32+
onSuccess: (_data, _variables, onMutateResult) => {
33+
expectTypeOf(onMutateResult).toEqualTypeOf<{ token: string }>()
34+
},
35+
onError: (_error, _variables, onMutateResult) => {
36+
expectTypeOf(onMutateResult).toEqualTypeOf<
37+
{ token: string } | undefined
38+
>()
39+
},
40+
})
41+
})
42+
43+
it('should allow explicit generic types', () => {
44+
const mutation = useMutation<string, Error, { id: number }>({
45+
mutationFn: (vars) => {
46+
expectTypeOf(vars).toEqualTypeOf<{ id: number }>()
47+
return Promise.resolve('result')
48+
},
49+
})
50+
51+
expectTypeOf(mutation.data).toEqualTypeOf<string | undefined>()
52+
expectTypeOf(mutation.error).toEqualTypeOf<Error | null>()
53+
})
54+
55+
it('should return correct UseMutationResult type', () => {
56+
const mutation = useMutation({
57+
mutationFn: () => Promise.resolve(42),
58+
})
59+
60+
expectTypeOf(mutation).toEqualTypeOf<
61+
UseMutationResult<number, DefaultError, void, unknown>
62+
>()
63+
})
64+
65+
it('should type mutateAsync with correct return type', () => {
66+
const mutation = useMutation({
67+
mutationFn: (id: string) => Promise.resolve(id.length),
68+
})
69+
70+
expectTypeOf(mutation.mutateAsync).toBeCallableWith('test')
71+
expectTypeOf(mutation.mutateAsync('test')).toEqualTypeOf<Promise<number>>()
72+
})
73+
74+
it('should default TVariables to void when mutationFn has no parameters', () => {
75+
const mutation = useMutation({
76+
mutationFn: () => Promise.resolve('data'),
77+
})
78+
79+
expectTypeOf(mutation.mutate).toBeCallableWith()
80+
})
81+
82+
it('should infer custom TError type', () => {
83+
class CustomError extends Error {
84+
code: number
85+
constructor(code: number) {
86+
super()
87+
this.code = code
88+
}
89+
}
90+
91+
const mutation = useMutation<string, CustomError>({
92+
mutationFn: () => Promise.resolve('data'),
93+
})
94+
95+
expectTypeOf(mutation.error).toEqualTypeOf<CustomError | null>()
96+
expectTypeOf(mutation.data).toEqualTypeOf<string | undefined>()
97+
})
98+
99+
it('should infer types for onSettled callback', () => {
100+
useMutation({
101+
mutationFn: () => Promise.resolve(42),
102+
onSettled: (data, error, _variables, _onMutateResult) => {
103+
expectTypeOf(data).toEqualTypeOf<number | undefined>()
104+
expectTypeOf(error).toEqualTypeOf<DefaultError | null>()
105+
},
106+
})
107+
})
108+
109+
it('should infer custom TError in onError callback', () => {
110+
class CustomError extends Error {
111+
code: number
112+
constructor(code: number) {
113+
super()
114+
this.code = code
115+
}
116+
}
117+
118+
useMutation<string, CustomError>({
119+
mutationFn: () => Promise.resolve('data'),
120+
onError: (error) => {
121+
expectTypeOf(error).toEqualTypeOf<CustomError>()
122+
},
123+
})
124+
})
125+
126+
it('should accept queryClient as second argument', () => {
127+
const queryClient = new QueryClient()
128+
129+
const mutation = useMutation(
130+
{
131+
mutationFn: () => Promise.resolve('data'),
132+
},
133+
queryClient,
134+
)
135+
136+
expectTypeOf(mutation.data).toEqualTypeOf<string | undefined>()
137+
})
138+
})

0 commit comments

Comments
 (0)