From 2ddfb1ccb24c5fcabd2e03c72f30240b5320bdc0 Mon Sep 17 00:00:00 2001
From: unnoq <contact@unnoq.com>
Date: Mon, 3 Mar 2025 10:21:25 +0700
Subject: [PATCH 1/3] feat(query-core): make `MutateFunction` optional
 undefinable-variables

---
 .../query-core/src/__tests__/types.test-d.tsx | 59 +++++++++++++++++++
 packages/query-core/src/types.ts              | 18 +++++-
 2 files changed, 75 insertions(+), 2 deletions(-)
 create mode 100644 packages/query-core/src/__tests__/types.test-d.tsx

diff --git a/packages/query-core/src/__tests__/types.test-d.tsx b/packages/query-core/src/__tests__/types.test-d.tsx
new file mode 100644
index 0000000000..0b0b4cd72d
--- /dev/null
+++ b/packages/query-core/src/__tests__/types.test-d.tsx
@@ -0,0 +1,59 @@
+import { describe, expectTypeOf, it } from 'vitest'
+import type { MutateFunction } from 'src/types'
+
+describe('MutateFunction', () => {
+  it('optional undefinable variables', () => {
+    const mutate = {} as MutateFunction<
+      unknown,
+      unknown,
+      number | undefined,
+      unknown
+    >
+
+    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
+      number | undefined
+    >()
+
+    mutate() // can be called with no arguments
+  })
+
+  it('required non-undefinable variables', () => {
+    const mutate = {} as MutateFunction<unknown, unknown, number, unknown>
+
+    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
+
+    // @ts-expect-error --- required variables
+    mutate()
+  })
+
+  describe('compatible with spread arguments pattern', () => {
+    // this is common pattern used internal so we need make sure it still works
+
+    it('optional undefinable variables', () => {
+      const mutate = {} as (
+        ...options: Parameters<
+          MutateFunction<unknown, unknown, number | undefined, unknown>
+        >
+      ) => void
+
+      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
+        number | undefined
+      >()
+
+      mutate() // can be called with no arguments
+    })
+
+    it('required non-undefinable variables', () => {
+      const mutate = {} as (
+        ...options: Parameters<
+          MutateFunction<unknown, unknown, number, unknown>
+        >
+      ) => void
+
+      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
+
+      // @ts-expect-error --- required variables
+      mutate()
+    })
+  })
+})
diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts
index 6d94daabc0..8e1c7bc8c8 100644
--- a/packages/query-core/src/types.ts
+++ b/packages/query-core/src/types.ts
@@ -1149,14 +1149,28 @@ export interface MutateOptions<
   ) => void
 }
 
+export type MutateFunctionRest<
+  TData = unknown,
+  TError = DefaultError,
+  TVariables = void,
+  TContext = unknown,
+> = undefined extends TVariables
+  ? [
+      variables?: TVariables,
+      options?: MutateOptions<TData, TError, TVariables, TContext>,
+    ]
+  : [
+      variables: TVariables,
+      options?: MutateOptions<TData, TError, TVariables, TContext>,
+    ]
+
 export type MutateFunction<
   TData = unknown,
   TError = DefaultError,
   TVariables = void,
   TContext = unknown,
 > = (
-  variables: TVariables,
-  options?: MutateOptions<TData, TError, TVariables, TContext>,
+  ...rest: MutateFunctionRest<TData, TError, TVariables, TContext>
 ) => Promise<TData>
 
 export interface MutationObserverBaseResult<

From 30858702fb524c8370b3013aed237f62b527fcc8 Mon Sep 17 00:00:00 2001
From: unnoq <contact@unnoq.com>
Date: Tue, 4 Mar 2025 19:46:15 +0700
Subject: [PATCH 2/3] test(query-core): MutateFunction

---
 .../src/__tests__/mutation.test-d.tsx         | 135 ++++++++++++++++++
 .../query-core/src/__tests__/types.test-d.tsx |  59 --------
 2 files changed, 135 insertions(+), 59 deletions(-)
 create mode 100644 packages/query-core/src/__tests__/mutation.test-d.tsx
 delete mode 100644 packages/query-core/src/__tests__/types.test-d.tsx

diff --git a/packages/query-core/src/__tests__/mutation.test-d.tsx b/packages/query-core/src/__tests__/mutation.test-d.tsx
new file mode 100644
index 0000000000..f5f15afdfc
--- /dev/null
+++ b/packages/query-core/src/__tests__/mutation.test-d.tsx
@@ -0,0 +1,135 @@
+import { describe, expectTypeOf, it } from 'vitest'
+import type { DefaultError, MutateFunction, MutateOptions } from 'src/types'
+
+describe('MutateFunction', () => {
+  it('void variables', () => {
+    const mutate = {} as MutateFunction
+
+    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
+      undefined | void
+    >()
+
+    expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
+      undefined | MutateOptions<unknown, DefaultError, void, unknown>
+    >()
+
+    mutate() // can be called with no arguments
+    mutate(undefined, {
+      onError: (e) => {
+        expectTypeOf(e).toEqualTypeOf<DefaultError>()
+      },
+    })
+  })
+
+  it('optional undefinable variables', () => {
+    const mutate = {} as MutateFunction<
+      unknown,
+      DefaultError,
+      number | undefined,
+      unknown
+    >
+
+    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
+      number | undefined
+    >()
+
+    expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
+      | undefined
+      | MutateOptions<unknown, DefaultError, number | undefined, unknown>
+    >()
+
+    mutate() // can be called with no arguments
+    mutate(undefined, {
+      onError: (e) => {
+        expectTypeOf(e).toEqualTypeOf<DefaultError>()
+      },
+    })
+  })
+
+  it('required non-undefinable variables', () => {
+    const mutate = {} as MutateFunction<unknown, DefaultError, number, unknown>
+
+    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
+
+    expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
+      undefined | MutateOptions<unknown, DefaultError, number, unknown>
+    >()
+
+    // @ts-expect-error --- required variables
+    mutate()
+    mutate(123, {
+      onError: (e) => {
+        expectTypeOf(e).toEqualTypeOf<DefaultError>()
+      },
+    })
+  })
+
+  describe('compatible with spread arguments pattern', () => {
+    // this is common pattern used internal so we need make sure it still works
+
+    it('void variables', () => {
+      const mutate = {} as (...options: Parameters<MutateFunction>) => void
+
+      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
+        undefined | void
+      >()
+
+      expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
+        undefined | MutateOptions<unknown, DefaultError, void, unknown>
+      >()
+
+      mutate() // can be called with no arguments
+      mutate(undefined, {
+        onError: (e) => {
+          expectTypeOf(e).toEqualTypeOf<DefaultError>()
+        },
+      })
+    })
+
+    it('optional undefinable variables', () => {
+      const mutate = {} as (
+        ...options: Parameters<
+          MutateFunction<unknown, DefaultError, number | undefined, unknown>
+        >
+      ) => void
+
+      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
+        number | undefined
+      >()
+
+      expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
+        | undefined
+        | MutateOptions<unknown, DefaultError, number | undefined, unknown>
+      >()
+
+      mutate() // can be called with no arguments
+      mutate(undefined, {
+        onError: (e) => {
+          expectTypeOf(e).toEqualTypeOf<DefaultError>()
+        },
+      })
+    })
+
+    it('required non-undefinable variables', () => {
+      const mutate = {} as (
+        ...options: Parameters<
+          MutateFunction<unknown, DefaultError, number, unknown>
+        >
+      ) => void
+
+      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
+
+      expectTypeOf<Parameters<typeof mutate>[1]>().toEqualTypeOf<
+        undefined | MutateOptions<unknown, DefaultError, number, unknown>
+      >()
+
+      // @ts-expect-error --- required variables
+      mutate()
+      mutate(123, {
+        onError: (e) => {
+          expectTypeOf(e).toEqualTypeOf<DefaultError>()
+        },
+      })
+    })
+  })
+})
diff --git a/packages/query-core/src/__tests__/types.test-d.tsx b/packages/query-core/src/__tests__/types.test-d.tsx
deleted file mode 100644
index 0b0b4cd72d..0000000000
--- a/packages/query-core/src/__tests__/types.test-d.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { describe, expectTypeOf, it } from 'vitest'
-import type { MutateFunction } from 'src/types'
-
-describe('MutateFunction', () => {
-  it('optional undefinable variables', () => {
-    const mutate = {} as MutateFunction<
-      unknown,
-      unknown,
-      number | undefined,
-      unknown
-    >
-
-    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
-      number | undefined
-    >()
-
-    mutate() // can be called with no arguments
-  })
-
-  it('required non-undefinable variables', () => {
-    const mutate = {} as MutateFunction<unknown, unknown, number, unknown>
-
-    expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
-
-    // @ts-expect-error --- required variables
-    mutate()
-  })
-
-  describe('compatible with spread arguments pattern', () => {
-    // this is common pattern used internal so we need make sure it still works
-
-    it('optional undefinable variables', () => {
-      const mutate = {} as (
-        ...options: Parameters<
-          MutateFunction<unknown, unknown, number | undefined, unknown>
-        >
-      ) => void
-
-      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<
-        number | undefined
-      >()
-
-      mutate() // can be called with no arguments
-    })
-
-    it('required non-undefinable variables', () => {
-      const mutate = {} as (
-        ...options: Parameters<
-          MutateFunction<unknown, unknown, number, unknown>
-        >
-      ) => void
-
-      expectTypeOf<Parameters<typeof mutate>[0]>().toEqualTypeOf<number>()
-
-      // @ts-expect-error --- required variables
-      mutate()
-    })
-  })
-})

From 02db0f2cfbc00237951c7ad9b7f543d17bdb6101 Mon Sep 17 00:00:00 2001
From: unnoq <contact@unnoq.com>
Date: Tue, 4 Mar 2025 19:52:07 +0700
Subject: [PATCH 3/3] test(query-core): MutateFunction

---
 .../src/__tests__/{mutation.test-d.tsx => mutations.test-d.tsx}   | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename packages/query-core/src/__tests__/{mutation.test-d.tsx => mutations.test-d.tsx} (100%)

diff --git a/packages/query-core/src/__tests__/mutation.test-d.tsx b/packages/query-core/src/__tests__/mutations.test-d.tsx
similarity index 100%
rename from packages/query-core/src/__tests__/mutation.test-d.tsx
rename to packages/query-core/src/__tests__/mutations.test-d.tsx