query icon indicating copy to clipboard operation
query copied to clipboard

Angular injectMutation: `onSuccess` loses type when `queryClient` is passed to `injectMutation`

Open 7schmiede opened this issue 1 year ago • 3 comments

Describe the bug

When the queryClient is passed in the injectMutation method, the return type of mutationFn is lost in the onSuccess method.

Your minimal, reproducible example

https://stackblitz.com/edit/stackblitz-starters-3zsk2e?file=test.ts

Steps to reproduce

import { injectMutation } from "@tanstack/angular-query-experimental";

// without queryClient 
export const foo = injectMutation(() => ({
    mutationFn: () => Promise.resolve({ foo: true }),
    onSuccess: (result) => {
        result.foo; // result: { foo: boolean; }
    }
}));

// with queryClient
export const bar = injectMutation((queryClient) => ({
    mutationFn: () => Promise.resolve({ bar: true }),
    onSuccess: (result) => {
        result.bar; // result: unknown
    }
}));

Expected behavior

Even if the queryClient is passed, the return type of the mutationFn should remain in the onSuccess method.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

  • OS: Windows 11
  • Browser: Edge Chromium
  • Version: 5.55.4

Tanstack Query adapter

angular-query

TanStack Query version

v5.55.4

TypeScript version

No response

Additional context

No response

7schmiede avatar Sep 11 '24 13:09 7schmiede

Yeah this is a really frustrating issue. I either have to choose between just injecting the query client at the top level, or manually typing all parameters in the callback functions

mevans avatar Sep 20 '24 09:09 mevans

Same here. Figured out, specifying the queryClient type does the trick for the moment. At least better than every method arguments.

injectMutation((client: QueryClient) => ({
}));

rklfss avatar Oct 18 '24 13:10 rklfss

One could fix this by wrapping TData with NoInfer<TData> in the MutationOptions type of the core package at https://github.com/TanStack/query/blob/main/packages/query-core/src/types.ts#L1005, but that would be a breaking change for all adapters.

ThiloAschebrock avatar Oct 18 '24 23:10 ThiloAschebrock

Hey, to all who reacted here: would you mind very much if I removed the client parameter? I am working towards a stable release and this isn't essential IMO.

Also the API to inject to inject the QueryClient became a bit less weird:

Now

client = inject(QueryClient) // This would result in an error before, but now works as expected

Before

client = injectQueryClient()

You can still use injectQueryClient and I think I'll keep it as convenience to easily pass a custom injector:

client = injectQueryClient({injector: this.injector})

If anybody wants to contribute the client parameter with types working properly we could re-add it.

arnoud-dv avatar Nov 18 '24 12:11 arnoud-dv

This happens with the select function in injectQuery too

Reproduction as unit tests:

packages/angular-query-experimental/src/tests/inject-query.test-d.ts

    test('should be possible to define a different TData than TQueryFnData using select with queryOptions spread into useQuery and passing queryClient', () => {
      const options = queryOptions({
        queryKey: ['key'],
        queryFn: () => Promise.resolve(1),
      })

      const query = injectQuery((client) => ({
        ...options,
        select: (data) => data > 1,
      }))

      expectTypeOf(query.data).toEqualTypeOf<Signal<boolean | undefined>>()
    })

packages/angular-query-experimental/src/tests/inject-mutation-types.test-d.ts

  test('onSuccess should receive the correct type when injectMutation passes queryClient', () => {
    injectMutation((_queryClient) => ({
      mutationFn: successMutator<{success: true}>,
      onSuccess: (data) => {
        expectTypeOf(data).toEqualTypeOf<{success: true}>()
      }
    }))
  })

arnoud-dv avatar Nov 19 '24 17:11 arnoud-dv