Skip to content

Commit 2215bb0

Browse files
dinwwwhTkDodoautofix-ci[bot]
authored
fix(query-core): make MutateFunction optional undefinable-variables (#8737)
* feat(query-core): make `MutateFunction` optional undefinable-variables * test(query-core): MutateFunction * test(query-core): MutateFunction * vue * ci: apply automated fixes * angular * fix adapter signatures * ci: apply automated fixes * changeset --------- Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent b4368c4 commit 2215bb0

10 files changed

Lines changed: 294 additions & 26 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@tanstack/angular-query-experimental': patch
3+
'@tanstack/lit-query': patch
4+
'@tanstack/preact-query': patch
5+
'@tanstack/query-core': patch
6+
'@tanstack/react-query': patch
7+
'@tanstack/solid-query': patch
8+
'@tanstack/svelte-query': patch
9+
'@tanstack/vue-query': patch
10+
---
11+
12+
fix: make mutation variables optional when `undefined extends TVariables`

‎packages/angular-query-experimental/src/inject-mutation.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ export function injectMutation<
8686
CreateMutateFunction<TData, TError, TVariables, TOnMutateResult>
8787
>(() => {
8888
const observer = observerSignal()
89-
return (variables, mutateOptions) => {
90-
observer.mutate(variables, mutateOptions).catch(noop)
89+
return (
90+
...args: Parameters<
91+
CreateMutateFunction<TData, TError, TVariables, TOnMutateResult>
92+
>
93+
) => {
94+
observer.mutate(args[0] as TVariables, args[1]).catch(noop)
9195
}
9296
})
9397

‎packages/lit-query/src/createMutationController.ts‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
MutationObserver,
33
type DefaultError,
4-
type MutateOptions,
4+
type MutateFunction,
55
type MutationObserverOptions,
66
type MutationObserverResult,
77
} from '@tanstack/query-core'
@@ -45,8 +45,9 @@ export type MutationResultAccessor<TData, TError, TVariables, TOnMutateResult> =
4545
* Throws synchronously if no `QueryClient` can be resolved.
4646
*/
4747
mutate: (
48-
variables: TVariables,
49-
options?: MutateOptions<TData, TError, TVariables, TOnMutateResult>,
48+
...args: Parameters<
49+
MutateFunction<TData, TError, TVariables, TOnMutateResult>
50+
>
5051
) => void
5152
/**
5253
* Starts the mutation and returns the observer promise.
@@ -190,14 +191,15 @@ class MutationController<
190191
}
191192

192193
mutate = (
193-
variables: TVariables,
194-
mutateOptions?: MutateOptions<TData, TError, TVariables, TOnMutateResult>,
194+
...args: Parameters<
195+
MutateFunction<TData, TError, TVariables, TOnMutateResult>
196+
>
195197
): void => {
196198
if (!this.syncClient() || !this.observer) {
197199
throw createMissingQueryClientError()
198200
}
199201

200-
void this.observer.mutate(variables, mutateOptions).catch(() => {
202+
void this.observer.mutate(args[0] as TVariables, args[1]).catch(() => {
201203
// Intentionally swallow in sync mutate path.
202204
})
203205
}
@@ -212,7 +214,7 @@ class MutationController<
212214
return Promise.reject(createMissingQueryClientError())
213215
}
214216

215-
return this.observer.mutate(...args)
217+
return this.observer.mutate(args[0] as TVariables, args[1])
216218
}
217219

218220
reset: MutationObserverResult<

‎packages/preact-query/src/useMutation.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ export function useMutation<
5252
const mutate = useCallback<
5353
UseMutateFunction<TData, TError, TVariables, TOnMutateResult>
5454
>(
55-
(variables, mutateOptions) => {
56-
observer.mutate(variables, mutateOptions).catch(noop)
55+
(
56+
...args: Parameters<
57+
UseMutateFunction<TData, TError, TVariables, TOnMutateResult>
58+
>
59+
) => {
60+
observer.mutate(args[0] as TVariables, args[1]).catch(noop)
5761
},
5862
[observer],
5963
)
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
import { describe, expectTypeOf, it } from 'vitest'
2+
3+
import type { DefaultError, MutateFunction, MutateOptions } from '../types'
4+
5+
describe('MutateFunction', () => {
6+
it('void variables', () => {
7+
const mutate = {} as MutateFunction
8+
9+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
10+
undefined | void
11+
>()
12+
13+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
14+
undefined | MutateOptions<unknown, DefaultError, void, unknown>
15+
>()
16+
17+
mutate() // can be called with no arguments
18+
mutate(undefined, {
19+
onError: (e) => {
20+
expectTypeOf(e).toEqualTypeOf<DefaultError>()
21+
},
22+
})
23+
})
24+
25+
it('optional undefinable variables', () => {
26+
const mutate = {} as MutateFunction<
27+
unknown,
28+
DefaultError,
29+
number | undefined,
30+
unknown
31+
>
32+
33+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
34+
number | undefined
35+
>()
36+
37+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
38+
| undefined
39+
| MutateOptions<unknown, DefaultError, number | undefined, unknown>
40+
>()
41+
42+
mutate() // can be called with no arguments
43+
mutate(undefined, {
44+
onError: (e) => {
45+
expectTypeOf(e).toEqualTypeOf<DefaultError>()
46+
},
47+
})
48+
})
49+
50+
it('unknown variables', () => {
51+
const mutate = {} as MutateFunction<unknown, DefaultError, unknown, unknown>
52+
53+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<unknown>()
54+
55+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
56+
undefined | MutateOptions<unknown, DefaultError, unknown, unknown>
57+
>()
58+
59+
mutate() // can be called with no arguments
60+
})
61+
62+
it('any variables', () => {
63+
const mutate = {} as MutateFunction<unknown, DefaultError, any, unknown>
64+
65+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<any>()
66+
67+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
68+
undefined | MutateOptions<unknown, DefaultError, any, unknown>
69+
>()
70+
71+
mutate() // can be called with no arguments
72+
})
73+
74+
it('void union variables', () => {
75+
const mutate = {} as MutateFunction<
76+
unknown,
77+
DefaultError,
78+
void | string,
79+
unknown
80+
>
81+
82+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
83+
void | string | undefined
84+
>()
85+
86+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
87+
undefined | MutateOptions<unknown, DefaultError, void | string, unknown>
88+
>()
89+
90+
mutate() // can be called with no arguments
91+
})
92+
93+
it('required non-undefinable variables', () => {
94+
const mutate = {} as MutateFunction<unknown, DefaultError, number, unknown>
95+
96+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
97+
98+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
99+
undefined | MutateOptions<unknown, DefaultError, number, unknown>
100+
>()
101+
102+
// @ts-expect-error --- required variables
103+
mutate()
104+
mutate(123, {
105+
onError: (e) => {
106+
expectTypeOf(e).toEqualTypeOf<DefaultError>()
107+
},
108+
})
109+
})
110+
111+
describe('compatible with spread arguments pattern', () => {
112+
// this is common pattern used internal so we need make sure it still works
113+
114+
it('void variables', () => {
115+
const mutate = {} as (...options: Parameters<MutateFunction>) => void
116+
117+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
118+
undefined | void
119+
>()
120+
121+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
122+
undefined | MutateOptions<unknown, DefaultError, void, unknown>
123+
>()
124+
125+
mutate() // can be called with no arguments
126+
mutate(undefined, {
127+
onError: (e) => {
128+
expectTypeOf(e).toEqualTypeOf<DefaultError>()
129+
},
130+
})
131+
})
132+
133+
it('optional undefinable variables', () => {
134+
const mutate = {} as (
135+
...options: Parameters<
136+
MutateFunction<unknown, DefaultError, number | undefined, unknown>
137+
>
138+
) => void
139+
140+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
141+
number | undefined
142+
>()
143+
144+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
145+
| undefined
146+
| MutateOptions<unknown, DefaultError, number | undefined, unknown>
147+
>()
148+
149+
mutate() // can be called with no arguments
150+
mutate(undefined, {
151+
onError: (e) => {
152+
expectTypeOf(e).toEqualTypeOf<DefaultError>()
153+
},
154+
})
155+
})
156+
157+
it('unknown variables', () => {
158+
const mutate = {} as (
159+
...options: Parameters<
160+
MutateFunction<unknown, DefaultError, unknown, unknown>
161+
>
162+
) => void
163+
164+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<unknown>()
165+
166+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
167+
undefined | MutateOptions<unknown, DefaultError, unknown, unknown>
168+
>()
169+
170+
mutate() // can be called with no arguments
171+
})
172+
173+
it('any variables', () => {
174+
const mutate = {} as (
175+
...options: Parameters<
176+
MutateFunction<unknown, DefaultError, any, unknown>
177+
>
178+
) => void
179+
180+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<any>()
181+
182+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
183+
undefined | MutateOptions<unknown, DefaultError, any, unknown>
184+
>()
185+
186+
mutate() // can be called with no arguments
187+
})
188+
189+
it('void union variables', () => {
190+
const mutate = {} as (
191+
...options: Parameters<
192+
MutateFunction<unknown, DefaultError, void | string, unknown>
193+
>
194+
) => void
195+
196+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
197+
void | string | undefined
198+
>()
199+
200+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
201+
undefined | MutateOptions<unknown, DefaultError, void | string, unknown>
202+
>()
203+
204+
mutate() // can be called with no arguments
205+
})
206+
207+
it('required non-undefinable variables', () => {
208+
const mutate = {} as (
209+
...options: Parameters<
210+
MutateFunction<unknown, DefaultError, number, unknown>
211+
>
212+
) => void
213+
214+
expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
215+
216+
expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
217+
undefined | MutateOptions<unknown, DefaultError, number, unknown>
218+
>()
219+
220+
// @ts-expect-error --- required variables
221+
mutate()
222+
mutate(123, {
223+
onError: (e) => {
224+
expectTypeOf(e).toEqualTypeOf<DefaultError>()
225+
},
226+
})
227+
})
228+
})
229+
})

‎packages/query-core/src/types.ts‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,14 +1176,28 @@ export interface MutateOptions<
11761176
) => void
11771177
}
11781178

1179+
export type MutateFunctionRest<
1180+
TData = unknown,
1181+
TError = DefaultError,
1182+
TVariables = void,
1183+
TOnMutateResult = unknown,
1184+
> = undefined extends TVariables
1185+
? [
1186+
variables?: TVariables,
1187+
options?: MutateOptions<TData, TError, TVariables, TOnMutateResult>,
1188+
]
1189+
: [
1190+
variables: TVariables,
1191+
options?: MutateOptions<TData, TError, TVariables, TOnMutateResult>,
1192+
]
1193+
11791194
export type MutateFunction<
11801195
TData = unknown,
11811196
TError = DefaultError,
11821197
TVariables = void,
11831198
TOnMutateResult = unknown,
11841199
> = (
1185-
variables: TVariables,
1186-
options?: MutateOptions<TData, TError, TVariables, TOnMutateResult>,
1200+
...rest: MutateFunctionRest<TData, TError, TVariables, TOnMutateResult>
11871201
) => Promise<TData>
11881202

11891203
export interface MutationObserverBaseResult<

‎packages/react-query/src/useMutation.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ export function useMutation<
5252
const mutate = React.useCallback<
5353
UseMutateFunction<TData, TError, TVariables, TOnMutateResult>
5454
>(
55-
(variables, mutateOptions) => {
56-
observer.mutate(variables, mutateOptions).catch(noop)
55+
(
56+
...args: Parameters<
57+
UseMutateFunction<TData, TError, TVariables, TOnMutateResult>
58+
>
59+
) => {
60+
observer.mutate(args[0] as TVariables, args[1]).catch(noop)
5761
},
5862
[observer],
5963
)

‎packages/solid-query/src/useMutation.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export function useMutation<
3636
TError,
3737
TVariables,
3838
TOnMutateResult
39-
> = (variables, mutateOptions) => {
40-
observer.mutate(variables, mutateOptions).catch(noop)
39+
> = (...args) => {
40+
observer.mutate(args[0] as TVariables, args[1]).catch(noop)
4141
}
4242

4343
const [state, setState] = createStore<

‎packages/svelte-query/src/createMutation.svelte.ts‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ export function createMutation<
4646
observer.setOptions(options())
4747
})
4848

49-
const mutate = <CreateMutateFunction<TData, TError, TVariables, TContext>>((
50-
variables,
51-
mutateOptions,
49+
const mutate: CreateMutateFunction<TData, TError, TVariables, TContext> = (
50+
...args
5251
) => {
53-
observer.mutate(variables, mutateOptions).catch(noop)
54-
})
52+
observer.mutate(args[0] as TVariables, args[1]).catch(noop)
53+
}
5554

5655
let result = $state(observer.getCurrentResult())
5756
watchChanges(

0 commit comments

Comments
 (0)