Skip to content

Commit 954e6e2

Browse files
authored
fix(query): unable to infer mutation context when onMutate has args (#200)
* fix(query): Unable to infer mutation context when onMutate requires arguments * improve
1 parent cf03cec commit 954e6e2

10 files changed

Lines changed: 45 additions & 57 deletions

File tree

packages/react-query/src/procedure-utils.test-d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ describe('ProcedureUtils', () => {
290290
it('infer correct mutation context type', () => {
291291
useMutation({
292292
...utils.mutationOptions({
293-
onMutate: () => ({ mutationContext: true }),
293+
onMutate: v => ({ mutationContext: true }),
294294
onError: (e, v, context) => {
295295
expectTypeOf(context?.mutationContext).toEqualTypeOf<undefined | boolean>()
296296
},

packages/react-query/src/procedure-utils.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Client, ClientContext } from '@orpc/client'
22
import type { MaybeOptionalOptions } from '@orpc/shared'
33
import type { InfiniteData } from '@tanstack/react-query'
4-
import type { InfiniteOptionsBase, InfiniteOptionsIn, MutationOptionsBase, MutationOptionsIn, QueryOptionsBase, QueryOptionsIn } from './types'
4+
import type { InfiniteOptionsBase, InfiniteOptionsIn, MutationOptions, MutationOptionsIn, QueryOptionsBase, QueryOptionsIn } from './types'
55
import { buildKey } from './key'
66

77
export interface ProcedureUtils<TClientContext extends ClientContext, TInput, TOutput, TError extends Error> {
@@ -17,11 +17,9 @@ export interface ProcedureUtils<TClientContext extends ClientContext, TInput, TO
1717
options: U & InfiniteOptionsIn<TClientContext, TInput, TOutput, TError, USelectData, UPageParam>
1818
): NoInfer<U & Omit<InfiniteOptionsBase<TOutput, TError, UPageParam>, keyof U>>
1919

20-
mutationOptions<U, UMutationContext>(
21-
...rest: MaybeOptionalOptions<
22-
U & MutationOptionsIn<TClientContext, TInput, TOutput, TError, UMutationContext>
23-
>
24-
): NoInfer<U & Omit<MutationOptionsBase<TInput, TOutput, TError>, keyof U>>
20+
mutationOptions<UMutationContext>(
21+
...rest: MaybeOptionalOptions<MutationOptionsIn<TClientContext, TInput, TOutput, TError, UMutationContext>>
22+
): MutationOptions<TInput, TOutput, TError, UMutationContext>
2523
}
2624

2725
export function createProcedureUtils<TClientContext extends ClientContext, TInput, TOutput, TError extends Error>(
@@ -31,29 +29,29 @@ export function createProcedureUtils<TClientContext extends ClientContext, TInpu
3129
return {
3230
call: client,
3331

34-
queryOptions(...[{ input, context, ...rest } = {}]) {
32+
queryOptions(...[options = {} as any]) {
3533
return {
36-
queryKey: buildKey(path, { type: 'query', input: input as any }),
37-
queryFn: ({ signal }) => client(input as any, { signal, context: context as any }),
38-
...(rest as any),
34+
queryKey: buildKey(path, { type: 'query', input: options.input }),
35+
queryFn: ({ signal }) => client(options.input, { signal, context: options.context }),
36+
...options,
3937
}
4038
},
4139

42-
infiniteOptions({ input, context, ...rest }) {
40+
infiniteOptions(options) {
4341
return {
44-
queryKey: buildKey(path, { type: 'infinite', input: input(rest.initialPageParam) as any }),
42+
queryKey: buildKey(path, { type: 'infinite', input: options.input(options.initialPageParam) as any }),
4543
queryFn: ({ pageParam, signal }) => {
46-
return client(input(pageParam as any), { signal, context: context as any })
44+
return client(options.input(pageParam as any), { signal, context: options.context as any })
4745
},
48-
...(rest as any),
46+
...(options as any),
4947
}
5048
},
5149

52-
mutationOptions(...[{ context, ...rest } = {}]) {
50+
mutationOptions(...[options = {} as any]) {
5351
return {
5452
mutationKey: buildKey(path, { type: 'mutation' }),
55-
mutationFn: input => client(input, { context: context as any }),
56-
...(rest as any),
53+
mutationFn: input => client(input, { context: options.context }),
54+
...(options as any),
5755
}
5856
},
5957
}

packages/react-query/src/types.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ export interface InfiniteOptionsBase<TOutput, TError extends Error, TPageParam>
2626

2727
export type MutationOptionsIn<TClientContext extends ClientContext, TInput, TOutput, TError extends Error, TMutationContext> =
2828
& (Record<never, never> extends TClientContext ? { context?: TClientContext } : { context: TClientContext })
29-
& UseMutationOptions<TOutput, TError, TInput, TMutationContext>
29+
& MutationOptions<TInput, TOutput, TError, TMutationContext>
3030

31-
export interface MutationOptionsBase<TInput, TOutput, TError extends Error> {
32-
mutationKey: QueryKey
33-
mutationFn(input: TInput): Promise<TOutput>
34-
retry?(failureCount: number, error: TError): boolean // this make tanstack can infer the TError type
35-
}
31+
export type MutationOptions<TInput, TOutput, TError extends Error, TMutationContext> = UseMutationOptions<TOutput, TError, TInput, TMutationContext>

packages/server/src/procedure-decorated.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export class DecoratedProcedure<
124124
>
125125
): Procedure<TInitialContext, TCurrentContext, TInputSchema, TOutputSchema, THandlerOutput, TErrorMap, TMeta>
126126
& ProcedureClient<TClientContext, TInputSchema, TOutputSchema, THandlerOutput, TErrorMap> {
127-
return Object.assign(createProcedureClient(this, ...rest), {
127+
return Object.assign(createProcedureClient(this, ...rest as any), {
128128
'~type': 'Procedure' as const,
129129
'~orpc': this['~orpc'],
130130
})

packages/shared/src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export type MaybeOptionalOptions<TOptions> =
2-
| [options: TOptions]
3-
| (Record<never, never> extends TOptions ? [] : never)
1+
export type MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions
2+
? [options?: TOptions]
3+
: [options: TOptions]
44

55
export type SetOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

packages/vue-colada/tests/e2e.test-d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ describe('.mutationOptions', () => {
7272
input: 'INVALID',
7373
})
7474

75-
// @ts-expect-error --- cache is invalid
7675
useMutation(orpc.ping.mutationOptions({
7776
context: {
77+
// @ts-expect-error --- cache is invalid
7878
cache: 123,
7979
},
8080
}))

packages/vue-query/src/procedure-utils.test-d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ describe('ProcedureUtils', () => {
277277
it('infer correct mutation context type', () => {
278278
useMutation({
279279
...utils.mutationOptions({
280-
onMutate: () => ({ mutationContext: true }),
280+
onMutate: v => ({ mutationContext: true }),
281281
onError: (e, v, context) => {
282282
expectTypeOf(context?.mutationContext).toEqualTypeOf<undefined | boolean>()
283283
},

packages/vue-query/src/procedure-utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ describe('createProcedureUtils', () => {
6161
expect(buildKeySpy).toHaveBeenCalledTimes(1)
6262
expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'mutation' })
6363

64-
await expect(options.mutationFn!('__input__')).resolves.toEqual('__output__')
64+
await expect((options as any).mutationFn('__input__')).resolves.toEqual('__output__')
6565
expect(client).toHaveBeenCalledTimes(1)
6666
expect(client).toBeCalledWith('__input__', { context: { batch: '__batch__' } })
6767
})

packages/vue-query/src/procedure-utils.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Client, ClientContext } from '@orpc/client'
22
import type { MaybeOptionalOptions } from '@orpc/shared'
33
import type { InfiniteData } from '@tanstack/vue-query'
4-
import type { InfiniteOptionsBase, InfiniteOptionsIn, MutationOptionsBase, MutationOptionsIn, QueryOptionsBase, QueryOptionsIn } from './types'
4+
import type { InfiniteOptionsBase, InfiniteOptionsIn, MutationOptions, MutationOptionsIn, QueryOptionsBase, QueryOptionsIn } from './types'
55
import { computed } from 'vue'
66
import { buildKey } from './key'
77
import { unrefDeep } from './utils'
@@ -19,11 +19,9 @@ export interface ProcedureUtils<TClientContext extends ClientContext, TInput, TO
1919
options: U & InfiniteOptionsIn<TClientContext, TInput, TOutput, TError, USelectData, UPageParam>
2020
): NoInfer<U & Omit<InfiniteOptionsBase<TOutput, TError, UPageParam>, keyof U>>
2121

22-
mutationOptions<U, UMutationContext>(
23-
...rest: MaybeOptionalOptions<
24-
U & MutationOptionsIn<TClientContext, TInput, TOutput, TError, UMutationContext>
25-
>
26-
): NoInfer<U & Omit<MutationOptionsBase<TInput, TOutput, TError>, keyof U>>
22+
mutationOptions<UMutationContext>(
23+
...rest: MaybeOptionalOptions<MutationOptionsIn<TClientContext, TInput, TOutput, TError, UMutationContext>>
24+
): MutationOptions<TInput, TOutput, TError, UMutationContext>
2725
}
2826

2927
export function createProcedureUtils<TClientContext extends ClientContext, TInput, TOutput, TError extends Error>(
@@ -33,31 +31,31 @@ export function createProcedureUtils<TClientContext extends ClientContext, TInpu
3331
return {
3432
call: client,
3533

36-
queryOptions(...[{ input, context, ...rest } = {}]) {
34+
queryOptions(...[options = {} as any]) {
3735
return {
38-
queryKey: computed(() => buildKey(path, { type: 'query', input: unrefDeep(input) as any })),
39-
queryFn: ({ signal }) => client(unrefDeep(input) as any, { signal, context: unrefDeep(context) as any }),
40-
...(rest as any),
36+
queryKey: computed(() => buildKey(path, { type: 'query', input: unrefDeep(options.input) })),
37+
queryFn: ({ signal }) => client(unrefDeep(options.input), { signal, context: unrefDeep(options.context) }),
38+
...options,
4139
}
4240
},
4341

44-
infiniteOptions({ input, context, ...rest }) {
42+
infiniteOptions(options) {
4543
return {
4644
queryKey: computed(() => {
47-
return buildKey(path, { type: 'infinite', input: unrefDeep(input(unrefDeep(rest.initialPageParam) as any) as any) })
45+
return buildKey(path, { type: 'infinite', input: unrefDeep(options.input(unrefDeep(options.initialPageParam) as any) as any) })
4846
}),
4947
queryFn: ({ pageParam, signal }) => {
50-
return client(unrefDeep(input(pageParam as any)) as any, { signal, context: unrefDeep(context) as any })
48+
return client(unrefDeep(options.input(pageParam as any)) as any, { signal, context: unrefDeep(options.context) as any })
5149
},
52-
...(rest as any),
50+
...(options as any),
5351
}
5452
},
5553

56-
mutationOptions(...[{ context, ...rest } = {}]) {
54+
mutationOptions(...[options = {} as any]) {
5755
return {
5856
mutationKey: buildKey(path, { type: 'mutation' }),
59-
mutationFn: input => client(input, { context: unrefDeep(context) as any }),
60-
...(rest as any),
57+
mutationFn: input => client(input, { context: unrefDeep(options.context) }),
58+
...(options as any),
6159
}
6260
},
6361
}

packages/vue-query/src/types.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,11 @@ export interface InfiniteOptionsBase<TOutput, TError extends Error, TPageParam>
4747

4848
export type MutationOptionsIn<TClientContext extends ClientContext, TInput, TOutput, TError extends Error, TMutationContext> =
4949
& (Record<never, never> extends TClientContext ? { context?: TClientContext } : { context: TClientContext })
50-
& {
50+
& MutationOptions<TInput, TOutput, TError, TMutationContext>
51+
52+
export type MutationOptions<TInput, TOutput, TError extends Error, TMutationContext> =
53+
{
5154
[P in keyof MutationObserverOptions<TOutput, TError, TInput, TMutationContext>]: MaybeRefDeep<MutationObserverOptions<TOutput, TError, TInput, TMutationContext>[P]>
52-
}
53-
& {
55+
} & {
5456
shallow?: MaybeRef<boolean>
5557
}
56-
57-
export interface MutationOptionsBase<TInput, TOutput, TError extends Error> {
58-
mutationKey: QueryKey
59-
mutationFn(input: TInput): Promise<TOutput>
60-
retry?(failureCount: number, error: TError): boolean // this help tanstack can infer TError
61-
}

0 commit comments

Comments
 (0)