T
TanStack15mo ago
rising-crimson

Type is not assignable to type mutate function

Hello all, I get this error
Type updateDummy is not assignable to type mutation function
Type updateDummy is not assignable to type mutation function
and I am unsure how to fix it. I followed the same pattern as my createDummy function, both of which write react query functions to make mutation calls to the database.
import { type UpdateDummyDto, type CreateDummyDto } from "@bookwave/api-client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { DummyApiKeys } from "@/features/dummy/queries";
import { apiClient } from "@/lib/api/api-client";
import { captureAndRethrowException } from "@/lib/error/capture-and-rethrow-exception";

export const useCreateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createDummy,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};

export const useUpdateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateDummy,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};

async function createDummy(dummy: CreateDummyDto) {
try {
// Artificial wait so you can see what happens on the UI while the request
// is in flight.
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});

const response = await apiClient.dummy.createOne(dummy);
return response;
} catch (err: unknown) {
captureAndRethrowException(err);
}
}

async function updateDummy(dummyId: string, dummy: UpdateDummyDto) {
try {
// Artificial wait so you can see what happens on the UI while the request
// is in flight.
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});

const response = await apiClient.dummy.updateOne(dummyId, dummy);
return response;
} catch (err: unknown) {
captureAndRethrowException(err);
}
}
import { type UpdateDummyDto, type CreateDummyDto } from "@bookwave/api-client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { DummyApiKeys } from "@/features/dummy/queries";
import { apiClient } from "@/lib/api/api-client";
import { captureAndRethrowException } from "@/lib/error/capture-and-rethrow-exception";

export const useCreateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createDummy,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};

export const useUpdateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateDummy,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};

async function createDummy(dummy: CreateDummyDto) {
try {
// Artificial wait so you can see what happens on the UI while the request
// is in flight.
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});

const response = await apiClient.dummy.createOne(dummy);
return response;
} catch (err: unknown) {
captureAndRethrowException(err);
}
}

async function updateDummy(dummyId: string, dummy: UpdateDummyDto) {
try {
// Artificial wait so you can see what happens on the UI while the request
// is in flight.
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});

const response = await apiClient.dummy.updateOne(dummyId, dummy);
return response;
} catch (err: unknown) {
captureAndRethrowException(err);
}
}
No description
14 Replies
sensitive-blue
sensitive-blue15mo ago
mutationFn only provides one parameter. You'll need to combine dummyId and dummy under one object
sensitive-blue
sensitive-blue15mo ago
sensitive-blue
sensitive-blue15mo ago
If your updateDummy method must be that way, you could do:
mutationFn: ({ dummyId, ...dummy }) => updateDummy(dummyId, dummy)
mutationFn: ({ dummyId, ...dummy }) => updateDummy(dummyId, dummy)
And invoke via something like:
// This dummy has dummyId on it
mutation.mutate(dummy)
// This dummy has dummyId on it
mutation.mutate(dummy)
rising-crimson
rising-crimsonOP15mo ago
Thank you @troywoy for your reply Should I be spreading the contents of the dummy object?
export const useUpdateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ dummyId, dummy }) => updateDummy(dummyId, dummy),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};
export const useUpdateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ dummyId, dummy }) => updateDummy(dummyId, dummy),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};
sensitive-blue
sensitive-blue15mo ago
Depends on how you call mutate
rising-crimson
rising-crimsonOP15mo ago
I'd like to keep the params for the createDummy api call unchanged:
async function updateDummy(dummyId: string, dummy: UpdateDummyDto) {
try {
// Artificial wait so you can see what happens on the UI while the request
// is in flight.
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});

const response = await apiClient.dummy.updateOne(dummyId, dummy);
return response;
} catch (err: unknown) {
captureAndRethrowException(err);
}
}
async function updateDummy(dummyId: string, dummy: UpdateDummyDto) {
try {
// Artificial wait so you can see what happens on the UI while the request
// is in flight.
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});

const response = await apiClient.dummy.updateOne(dummyId, dummy);
return response;
} catch (err: unknown) {
captureAndRethrowException(err);
}
}
When I implement this code change:
export const useUpdateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ dummyId, dummy }) => updateDummy(dummyId, dummy),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};
export const useUpdateDummyMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ dummyId, dummy }) => updateDummy(dummyId, dummy),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: DummyApiKeys.fetchAll(),
});
},
});
};
sensitive-blue
sensitive-blue15mo ago
And how do you call mutate from useUpdateDummyMutation?
rising-crimson
rising-crimsonOP15mo ago
I get new TS error properties don't exist on type 'void'
sensitive-blue
sensitive-blue15mo ago
You need to type the ({ dummyId, dummy }) => portion
sensitive-blue
sensitive-blue15mo ago
That's a sloppy example
rising-crimson
rising-crimsonOP15mo ago
I call useMutate as part of a long form submission, here's the relevant part:
const updateDummyMutation = useUpdateDummyMutation();
const doSubmit = handleSubmit(async (fields) => {
const dummy = {
foo: fields.foo,
bar: fields.bar,
content: fields.content,
};
try {
await updateDummyMutation.mutateAsync({ dummyId, dummy });
reset();
} catch (err: unknown) {
console.log(err);
}
});
const updateDummyMutation = useUpdateDummyMutation();
const doSubmit = handleSubmit(async (fields) => {
const dummy = {
foo: fields.foo,
bar: fields.bar,
content: fields.content,
};
try {
await updateDummyMutation.mutateAsync({ dummyId, dummy });
reset();
} catch (err: unknown) {
console.log(err);
}
});
sensitive-blue
sensitive-blue15mo ago
You have two options there. Either spread ...dummy on the mutateAsync line:
await updateDummyMutation.mutateAsync({ dummyId, ...dummy });
await updateDummyMutation.mutateAsync({ dummyId, ...dummy });
Or put dummyId onto the const dummy object and simply use that:
const dummy = {
dummyId,
foo: fields.foo,
bar: fields.bar,
content: fields.content,
};

await updateDummyMutation.mutateAsync(dummy);
const dummy = {
dummyId,
foo: fields.foo,
bar: fields.bar,
content: fields.content,
};

await updateDummyMutation.mutateAsync(dummy);
rising-crimson
rising-crimsonOP15mo ago
@troywoy thank you very much. You have helped immensely.

Did you find this page helpful?