Skip to content

Commit 2cf3ec9

Browse files
authored
fix(types): onMutateResult is always defined in onSuccess callback (#9677)
* fix(types): onMutateResult is always defined in onSuccess callback this is guaranteed because if onMutate fails or rejects, onSuccess is never called. if onMutate is not present, the type will be unknown * chore: fix tests
1 parent fcd23c9 commit 2cf3ec9

File tree

5 files changed

+101
-9
lines changed

5 files changed

+101
-9
lines changed

packages/angular-query-experimental/src/__tests__/mutation-options.test-d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ describe('mutationOptions', () => {
6767
return { name: 'onMutateResult' }
6868
},
6969
onSuccess: (_data, _variables, onMutateResult) => {
70-
expectTypeOf(onMutateResult).toEqualTypeOf<
71-
{ name: string } | undefined
72-
>()
70+
expectTypeOf(onMutateResult).toEqualTypeOf<{ name: string }>()
7371
},
7472
})
7573
})
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { describe, expectTypeOf, it } from 'vitest'
2+
import { QueryClient } from '../queryClient'
3+
import { MutationObserver } from '../mutationObserver'
4+
5+
describe('mutation', () => {
6+
describe('onMutate', () => {
7+
it('should have onMutateResult undefined if undefined is explicitly returned', () => {
8+
new MutationObserver(new QueryClient(), {
9+
mutationFn: (variables: number) => {
10+
return Promise.resolve(String(variables))
11+
},
12+
onMutate: () => {
13+
return undefined
14+
},
15+
onSuccess: (data, variables, onMutateResult) => {
16+
expectTypeOf(data).toEqualTypeOf<string>()
17+
expectTypeOf(variables).toEqualTypeOf<number>()
18+
expectTypeOf(onMutateResult).toEqualTypeOf<undefined>()
19+
},
20+
onError: (_data, _variables, onMutateResult) => {
21+
expectTypeOf(onMutateResult).toEqualTypeOf<undefined>()
22+
},
23+
onSettled: (_data, _error, _variables, onMutateResult) => {
24+
expectTypeOf(onMutateResult).toEqualTypeOf<undefined>()
25+
},
26+
})
27+
})
28+
29+
it('should have unknown onMutateResult if onMutate is left out', () => {
30+
new MutationObserver(new QueryClient(), {
31+
mutationFn: (variables: number) => {
32+
return Promise.resolve(String(variables))
33+
},
34+
onSuccess: (_data, _variables, onMutateResult) => {
35+
expectTypeOf(onMutateResult).toEqualTypeOf<unknown>()
36+
},
37+
onError: (_data, _variables, onMutateResult) => {
38+
expectTypeOf(onMutateResult).toEqualTypeOf<unknown>()
39+
},
40+
onSettled: (_data, _error, _variables, onMutateResult) => {
41+
expectTypeOf(onMutateResult).toEqualTypeOf<unknown>()
42+
},
43+
})
44+
})
45+
46+
it('should infer onMutateResult', () => {
47+
new MutationObserver(new QueryClient(), {
48+
mutationFn: (variables: number) => {
49+
return Promise.resolve(String(variables))
50+
},
51+
onMutate: () => {
52+
return Promise.resolve({ foo: 'bar' })
53+
},
54+
onSuccess: (_data, _variables, onMutateResult) => {
55+
expectTypeOf(onMutateResult).toEqualTypeOf<{ foo: string }>()
56+
},
57+
onError: (_data, _variables, onMutateResult) => {
58+
expectTypeOf(onMutateResult).toEqualTypeOf<
59+
{ foo: string } | undefined
60+
>()
61+
},
62+
onSettled: (_data, _error, _variables, onMutateResult) => {
63+
expectTypeOf(onMutateResult).toEqualTypeOf<
64+
{ foo: string } | undefined
65+
>()
66+
},
67+
})
68+
})
69+
70+
it('should include undefined in the union if explicitly returned', () => {
71+
new MutationObserver(new QueryClient(), {
72+
mutationFn: (variables: number) => {
73+
return Promise.resolve(String(variables))
74+
},
75+
onMutate: () => {
76+
return Math.random() > 0.5 ? { foo: 'bar' } : undefined
77+
},
78+
onSuccess: (_data, _variables, onMutateResult) => {
79+
expectTypeOf(onMutateResult).toEqualTypeOf<
80+
{ foo: string } | undefined
81+
>()
82+
},
83+
onError: (_data, _variables, onMutateResult) => {
84+
expectTypeOf(onMutateResult).toEqualTypeOf<
85+
{ foo: string } | undefined
86+
>()
87+
},
88+
onSettled: (_data, _error, _variables, onMutateResult) => {
89+
expectTypeOf(onMutateResult).toEqualTypeOf<
90+
{ foo: string } | undefined
91+
>()
92+
},
93+
})
94+
})
95+
})
96+
})

packages/query-core/src/mutation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ export class Mutation<
244244
await this.options.onSuccess?.(
245245
data,
246246
variables,
247-
this.state.context,
247+
this.state.context!,
248248
mutationFnContext,
249249
)
250250

packages/query-core/src/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,11 +1113,11 @@ export interface MutationOptions<
11131113
onMutate?: (
11141114
variables: TVariables,
11151115
context: MutationFunctionContext,
1116-
) => Promise<TOnMutateResult | undefined> | TOnMutateResult | undefined
1116+
) => Promise<TOnMutateResult> | TOnMutateResult
11171117
onSuccess?: (
11181118
data: TData,
11191119
variables: TVariables,
1120-
onMutateResult: TOnMutateResult | undefined,
1120+
onMutateResult: TOnMutateResult,
11211121
context: MutationFunctionContext,
11221122
) => Promise<unknown> | unknown
11231123
onError?: (

packages/react-query/src/__tests__/mutationOptions.test-d.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ describe('mutationOptions', () => {
6363
return { name: 'onMutateResult' }
6464
},
6565
onSuccess: (_data, _variables, onMutateResult) => {
66-
expectTypeOf(onMutateResult).toEqualTypeOf<
67-
{ name: string } | undefined
68-
>()
66+
expectTypeOf(onMutateResult).toEqualTypeOf<{ name: string }>()
6967
},
7068
})
7169
})

0 commit comments

Comments
 (0)