Dev9999
Dev9999

Reputation: 51

How to pass correct types to the react query useMutation hook?

Below is my code :

import { api } from 'api_v2/init';
import { DomainList, RedirectUrl, ZeusResponseSingle } from 'api_v2/zeus/types';
import { useMutation, useQueryClient } from 'react-query';

import { toast } from '@simpplr/athena-ui';
import { t } from '@simpplr/athena-utils';

type MutationFn = (apps: string) => Promise<RedirectUrl | null>;
type DomainMutationFn = (
  domainList: DomainList
) => Promise<ZeusResponseSingle<DomainList> | null>;

type MutationType = MutationFn | DomainMutationFn;

export const useSaveAllDomains = (provider: string) => {
  const queryClient = useQueryClient();

  const appUrlMethod =
    provider === 'Microsoft'
      ? api.manageApp.connectApp
      : api.domains.createDomains;

  const { mutate, isLoading } = useMutation<MutationType>(appUrlMethod, {
    onSuccess: (data) => {
      if (provider === 'Microsoft') {
        window.location.replace(data.redirectUrl);
      }
      toast.success(t('common.saved_changes_flash'));
    },
    onError: (error) => {
      toast.danger(error?.message || t('common.error_message'));
    },
    onSettled: () => {
      queryClient.invalidateQueries(['domains']);
    },
  });

  return { mutate, isLoading };
};

Now, inside useMutationHook Typescript is complaining me on appUrlMethod as :

const appUrlMethod: ((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>) No overload matches this call.   Overload 1 of 4, '(mutationFn: MutationFunction<MutationType, void>, options?: Omit<UseMutationOptions<MutationType, unknown, void, unknown>, "mutationFn"> | undefined): UseMutationResult<...>', gave the following error.
    Argument of type '((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)' is not assignable to parameter of type 'MutationFunction<MutationType, void>'.
      Type '(apps: string) => Promise<RedirectUrl | null>' is not assignable to type 'MutationFunction<MutationType, void>'.
        Types of parameters 'apps' and 'variables' are incompatible.
          Type 'void' is not assignable to type 'string'.   Overload 2 of 4, '(mutationKey: MutationKey, options?: Omit<UseMutationOptions<MutationType, unknown, void, unknown>, "mutationKey"> | undefined): UseMutationResult<...>', gave the following error.
    Argument of type '((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)' is not assignable to parameter of type 'MutationKey'.
      Type '(apps: string) => Promise<RedirectUrl | null>' is not assignable to type 'MutationKey'.   Overload 3 of 4, '(mutationKey: MutationKey, mutationFn?: MutationFunction<MutationType, void> | undefined, options?: Omit<UseMutationOptions<MutationType, unknown, void, unknown>, "mutationFn" | "mutationKey"> | undefined): UseMutationResult<...>', gave the following error.
    Argument of type '((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)' is not assignable to parameter of type 'MutationKey'.

How can i fix this Typescript error ? I have tried going through the reqct-query documentation but didn't get any proper understanding how to pass the correct types to useMutation hook.

Edit: My appUrlMethod type is a union of these two :

const appUrlMethod: ((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)

where mentioned types are as :

export type ZeusResponse = {
  status: number | string;
  message: string;
  responseTimeStamp?: number;
};

export type ZeusResponseSingle<T> = ZeusResponse & {
  result: T;
};

export type ZeusResponseResult<T> = {
  result: NonNullable<T>;
};

export type Domain = {
  domainName: string;
};

export type MicrosoftDomain = Domain & {
  domainId: string;
};

export type BoxDomainList = Array<Domain>;

export type GoogleCalendarDomainList = Array<Domain>;
export type GoogleDriveDomainList = Array<Domain>;

export type GoogleDomainList = {
  googleCalendarDomainList?: GoogleCalendarDomainList;
  googleDriveDomainList?: GoogleDriveDomainList;
};

export type MicrosoftDomainList = {
  outlookDomainList: Array<MicrosoftDomain>;
  onedriveDomainList?: Array<MicrosoftDomain>;
  sharepointDomainList?: Array<MicrosoftDomain>;
};

export type DomainList = {
  googleDomainList?: GoogleDomainList;
  boxDomainList?: BoxDomainList;
  microsoftDomainList?: MicrosoftDomainList;
};

export type DeleteDomainList = {
  boxDomainList?: BoxDomainList;
  googleCalendarDomainList?: GoogleCalendarDomainList;
  googleDriveDomainList?: GoogleDriveDomainList;
};

export type RedirectUrl = {
  redirectUrl: string;
};

I have tried letting Typescript infer the type by doing this :

const { mutate, isLoading } = useMutation(appUrlMethod, {
    onSuccess: (data) => {
....

}

But still getting Typescript error on appUrlMethod as No overload matches this call.

No overload matches this call.
  Overload 1 of 4, '(mutationFn: MutationFunction<RedirectUrl | null, string>, options?: Omit<UseMutationOptions<RedirectUrl | null, unknown, string, unknown>, "mutationFn"> | undefined): UseMutationResult<...>', gave the following error.
    Argument of type '((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)' is not assignable to parameter of type 'MutationFunction<RedirectUrl | null, string>'.
      Type '(domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>' is not assignable to type 'MutationFunction<RedirectUrl | null, string>'.
        Types of parameters 'domainList' and 'variables' are incompatible.
          Type 'string' has no properties in common with type 'DomainList'.
  Overload 2 of 4, '(mutationKey: MutationKey, options?: Omit<UseMutationOptions<unknown, unknown, void, unknown>, "mutationKey"> | undefined): UseMutationResult<unknown, unknown, void, unknown>', gave the following error.
    Argument of type '((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)' is not assignable to parameter of type 'MutationKey'.
      Type '(apps: string) => Promise<RedirectUrl | null>' is not assignable to type 'MutationKey'.
  Overload 3 of 4, '(mutationKey: MutationKey, mutationFn?: MutationFunction<unknown, void> | undefined, options?: Omit<UseMutationOptions<unknown, unknown, void, unknown>, "mutationFn" | "mutationKey"> | undefined): UseMutationResult<...>', gave the following error.
    Argument of type '((apps: string) => Promise<RedirectUrl | null>) | ((domainList: DomainList) => Promise<ZeusResponseSingle<DomainList> | null>)' is not assignable to parameter of type 'MutationKey'.

Upvotes: 0

Views: 2340

Answers (1)

TkDodo
TkDodo

Reputation: 28733

You best let type inference work for you. What happens if you write:

const { mutate, isLoading } = useMutation(appUrlMethod)

if appUrlMethod is typed well (which you're not showing 🤷‍♂️) it should just work. None of the type shenanigans are needed. The more your TS code looks like JS, the better.

Here's a TypeScript playground showing that: https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCyyYEMbAQB2cAvnAGZQQhwDkAAnkangMYDWA9FOrmzAC0AR2TooATzoAoaW2Ks4uMGACqUADaZ0MABYQAJnAC8S1BKJs4ACmBEwOAFxxWUOwHMAlCYB8cOw4wsvIs8CA4+IQkpmhYEQTE1spqmtp6hgA0iNJwcMQAyshsbOioqM7WBvi43sZ+CDm5cCGoEBroAHQaEO6V1Z6NuVxcTaNNAHoA-I2k0qQD0uF4CUQdVXjSw2O5U0A

Upvotes: 1

Related Questions