From 3969967068cda382c35c4e1f33c1d449b8feea03 Mon Sep 17 00:00:00 2001 From: Johan Lipecki Date: Fri, 10 Oct 2025 00:35:08 +0200 Subject: [PATCH 1/2] Support latest react-query mutation typings --- spec/react-query/mutations.spec.ts | 4 +- spec/react-query/rapini-mutation.spec.ts | 20 +- src/react-query/mutations.ts | 1 + src/react-query/rapini-mutation.ts | 346 +++++------------------ 4 files changed, 77 insertions(+), 294 deletions(-) diff --git a/spec/react-query/mutations.spec.ts b/spec/react-query/mutations.spec.ts index f75dbc2..3cd7588 100644 --- a/spec/react-query/mutations.spec.ts +++ b/spec/react-query/mutations.spec.ts @@ -8,8 +8,8 @@ const expected = `type MutationConfigs = { }; function makeMutations(requests: Requests, config?: Config["mutations"]) { return { - useCreatePet: (options?: Omit, unknown, Parameters[0], unknown>, "mutationFn">) => useRapiniMutation, unknown, Parameters[0]>(payload => requests.createPet(payload), config?.useCreatePet, options), - useAddPetPhoto: (petId: string, options?: Omit, unknown, Parameters[0], unknown>, "mutationFn">) => useRapiniMutation, unknown, Parameters[0]>(payload => requests.addPetPhoto(payload, petId), config?.useAddPetPhoto, options) + useCreatePet: (options?: Omit, unknown, Parameters[0], unknown>, "mutationFn">) => useRapiniMutation, unknown, Parameters[0], unknown>(payload => requests.createPet(payload), config?.useCreatePet, options), + useAddPetPhoto: (petId: string, options?: Omit, unknown, Parameters[0], unknown>, "mutationFn">) => useRapiniMutation, unknown, Parameters[0], unknown>(payload => requests.addPetPhoto(payload, petId), config?.useAddPetPhoto, options) } as const; } `; diff --git a/spec/react-query/rapini-mutation.spec.ts b/spec/react-query/rapini-mutation.spec.ts index 86a3f76..797cb4f 100644 --- a/spec/react-query/rapini-mutation.spec.ts +++ b/spec/react-query/rapini-mutation.spec.ts @@ -1,22 +1,22 @@ import { makeRapiniMutation } from "../../src/react-query/rapini-mutation"; import { compile } from "../test.utils"; -const expected = `function useRapiniMutation(mutationFn: MutationFunction, config?: (queryClient: QueryClient) => Pick, "onSuccess" | "onSettled" | "onError">, options?: Omit, "mutationFn">): UseMutationResult { +const expected = `function useRapiniMutation(mutationFn: MutationFunction, config?: (queryClient: QueryClient) => Pick, "onSuccess" | "onSettled" | "onError">, options?: Omit, "mutationFn">): UseMutationResult { const { onSuccess, onError, onSettled, ...rest } = options ?? {}; const queryClient = useQueryClient(); const conf = config?.(queryClient); const mutationOptions: typeof options = { - onSuccess: (data: TData, variables: TVariables, context: TContext) => { - conf?.onSuccess?.(data, variables, context); - onSuccess?.(data, variables, context); + onSuccess: (...args) => { + conf?.onSuccess?.(...args); + onSuccess?.(...args); }, - onError: (error: TError, variables: TVariables, context?: TContext) => { - conf?.onError?.(error, variables, context); - onError?.(error, variables, context); + onError: (...args) => { + conf?.onError?.(...args); + onError?.(...args); }, - onSettled: (data: TData | undefined, error: TError | null, variables: TVariables, context?: TContext) => { - conf?.onSettled?.(data, error, variables, context); - onSettled?.(data, error, variables, context); + onSettled: (...args) => { + conf?.onSettled?.(...args); + onSettled?.(...args); }, ...rest }; diff --git a/src/react-query/mutations.ts b/src/react-query/mutations.ts index fe75cc2..e2ffa6d 100644 --- a/src/react-query/mutations.ts +++ b/src/react-query/mutations.ts @@ -232,6 +232,7 @@ function makeProperty( ) ) : ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword), ], /*args*/ [ ts.factory.createArrowFunction( diff --git a/src/react-query/rapini-mutation.ts b/src/react-query/rapini-mutation.ts index eeab62f..9838040 100644 --- a/src/react-query/rapini-mutation.ts +++ b/src/react-query/rapini-mutation.ts @@ -3,6 +3,65 @@ import ts from "typescript"; export const RAPINI_MUTATION_ID = "useRapiniMutation"; export function makeRapiniMutation() { + const makeForwardingHandler = ( + name: "onSuccess" | "onError" | "onSettled" + ) => { + return ts.factory.createPropertyAssignment( + ts.factory.createIdentifier(name), + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + ts.factory.createToken(ts.SyntaxKind.DotDotDotToken), + ts.factory.createIdentifier("args"), + undefined, + undefined, + undefined + ), + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [ + ts.factory.createExpressionStatement( + ts.factory.createCallChain( + ts.factory.createPropertyAccessChain( + ts.factory.createIdentifier("conf"), + ts.factory.createToken(ts.SyntaxKind.QuestionDotToken), + ts.factory.createIdentifier(name) + ), + ts.factory.createToken(ts.SyntaxKind.QuestionDotToken), + undefined, + [ + ts.factory.createSpreadElement( + ts.factory.createIdentifier("args") + ), + ] + ) + ), + ts.factory.createExpressionStatement( + ts.factory.createCallChain( + ts.factory.createIdentifier(name), + ts.factory.createToken(ts.SyntaxKind.QuestionDotToken), + undefined, + [ + ts.factory.createSpreadElement( + ts.factory.createIdentifier("args") + ), + ] + ) + ), + ], + true + ) + ) + ); + }; + const forwardingHandlers = ["onSuccess", "onError", "onSettled"].map( + (handler) => makeForwardingHandler(handler as "onSuccess" | "onError" | "onSettled") + ); return ts.factory.createFunctionDeclaration( undefined, undefined, @@ -28,7 +87,7 @@ export function makeRapiniMutation() { ), ts.factory.createTypeParameterDeclaration( undefined, - ts.factory.createIdentifier("TContext"), + ts.factory.createIdentifier("TOnMutateResult"), undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword) ), @@ -93,7 +152,7 @@ export function makeRapiniMutation() { undefined ), ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TContext"), + ts.factory.createIdentifier("TOnMutateResult"), undefined ), ] @@ -138,7 +197,7 @@ export function makeRapiniMutation() { undefined ), ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TContext"), + ts.factory.createIdentifier("TOnMutateResult"), undefined ), ] @@ -167,7 +226,7 @@ export function makeRapiniMutation() { undefined ), ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TContext"), + ts.factory.createIdentifier("TOnMutateResult"), undefined ), ] @@ -267,284 +326,7 @@ export function makeRapiniMutation() { ), ts.factory.createObjectLiteralExpression( [ - ts.factory.createPropertyAssignment( - ts.factory.createIdentifier("onSuccess"), - ts.factory.createArrowFunction( - undefined, - undefined, - [ - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("data"), - undefined, - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TData"), - undefined - ), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("variables"), - undefined, - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TVariables"), - undefined - ), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("context"), - undefined, - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TContext"), - undefined - ), - undefined - ), - ], - undefined, - ts.factory.createToken( - ts.SyntaxKind.EqualsGreaterThanToken - ), - ts.factory.createBlock( - [ - ts.factory.createExpressionStatement( - ts.factory.createCallChain( - ts.factory.createPropertyAccessChain( - ts.factory.createIdentifier("conf"), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - ts.factory.createIdentifier("onSuccess") - ), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - undefined, - [ - ts.factory.createIdentifier("data"), - ts.factory.createIdentifier("variables"), - ts.factory.createIdentifier("context"), - ] - ) - ), - ts.factory.createExpressionStatement( - ts.factory.createCallChain( - ts.factory.createIdentifier("onSuccess"), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - undefined, - [ - ts.factory.createIdentifier("data"), - ts.factory.createIdentifier("variables"), - ts.factory.createIdentifier("context"), - ] - ) - ), - ], - true - ) - ) - ), - ts.factory.createPropertyAssignment( - ts.factory.createIdentifier("onError"), - ts.factory.createArrowFunction( - undefined, - undefined, - [ - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("error"), - undefined, - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TError"), - undefined - ), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("variables"), - undefined, - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TVariables"), - undefined - ), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("context"), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TContext"), - undefined - ), - undefined - ), - ], - undefined, - ts.factory.createToken( - ts.SyntaxKind.EqualsGreaterThanToken - ), - ts.factory.createBlock( - [ - ts.factory.createExpressionStatement( - ts.factory.createCallChain( - ts.factory.createPropertyAccessChain( - ts.factory.createIdentifier("conf"), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - ts.factory.createIdentifier("onError") - ), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - undefined, - [ - ts.factory.createIdentifier("error"), - ts.factory.createIdentifier("variables"), - ts.factory.createIdentifier("context"), - ] - ) - ), - ts.factory.createExpressionStatement( - ts.factory.createCallChain( - ts.factory.createIdentifier("onError"), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - undefined, - [ - ts.factory.createIdentifier("error"), - ts.factory.createIdentifier("variables"), - ts.factory.createIdentifier("context"), - ] - ) - ), - ], - true - ) - ) - ), - ts.factory.createPropertyAssignment( - ts.factory.createIdentifier("onSettled"), - ts.factory.createArrowFunction( - undefined, - undefined, - [ - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("data"), - undefined, - ts.factory.createUnionTypeNode([ - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TData"), - undefined - ), - ts.factory.createKeywordTypeNode( - ts.SyntaxKind.UndefinedKeyword - ), - ]), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("error"), - undefined, - ts.factory.createUnionTypeNode([ - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TError"), - undefined - ), - ts.factory.createLiteralTypeNode( - ts.factory.createNull() - ), - ]), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("variables"), - undefined, - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TVariables"), - undefined - ), - undefined - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - ts.factory.createIdentifier("context"), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier("TContext"), - undefined - ), - undefined - ), - ], - undefined, - ts.factory.createToken( - ts.SyntaxKind.EqualsGreaterThanToken - ), - ts.factory.createBlock( - [ - ts.factory.createExpressionStatement( - ts.factory.createCallChain( - ts.factory.createPropertyAccessChain( - ts.factory.createIdentifier("conf"), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - ts.factory.createIdentifier("onSettled") - ), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - undefined, - [ - ts.factory.createIdentifier("data"), - ts.factory.createIdentifier("error"), - ts.factory.createIdentifier("variables"), - ts.factory.createIdentifier("context"), - ] - ) - ), - ts.factory.createExpressionStatement( - ts.factory.createCallChain( - ts.factory.createIdentifier("onSettled"), - ts.factory.createToken( - ts.SyntaxKind.QuestionDotToken - ), - undefined, - [ - ts.factory.createIdentifier("data"), - ts.factory.createIdentifier("error"), - ts.factory.createIdentifier("variables"), - ts.factory.createIdentifier("context"), - ] - ) - ), - ], - true - ) - ) - ), + ...forwardingHandlers, ts.factory.createSpreadAssignment( ts.factory.createIdentifier("rest") ), From 213c06debafcf09fb1ddc7462e0ad9e8e949f8fd Mon Sep 17 00:00:00 2001 From: Johan Lipecki Date: Fri, 10 Oct 2025 00:46:27 +0200 Subject: [PATCH 2/2] add changelog for pull request --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index fea8127..77c4805 100644 --- a/changelog.md +++ b/changelog.md @@ -55,3 +55,7 @@ A major release with breaking changes. Involves updating type signatures to matc ### 3.5.3 - Fix for issue #48: Make context parameter required in onSuccess callback to match React Query's types + +### 3.5.4 + +- Fix for @tanstack/query v5.89.0 onError, onSuccess and onSettled signature change referenced in issue 9660