Consider a custom useSignUp hook which mutate() function takes some fields (name and email in this example):
export default function App() {
const name = "David";
const email = "[email protected]";
const signupMutation = useSignUp();
return (
<button
onClick={() => {
signupMutation.mutate(
{ name, email },
{
onSuccess: (result) => {
...
},
onError: (result) => {
// Wanted: result of type ErrorResult<"name" | "email">
}
}
);
}}
>
Sign Up
</button>
);
}
I'd like onError's result to be of type ErrorResponse<"name" | "email"> in this case. But, I get ErrorResponse<string>.
Why is that? How could I instruct TypeScript to infer the type to be specific based on the passed data (i.e. "name" | "email", not string)?
Here is how I typed useSignUp:
type SuccessResponse = {
userId: string;
};
type ErrorResponse<T> = {
userId?: string;
formErrors?: Array<{
field: T;
type: string;
}>;
};
export const useSignUp = <T extends string>() => {
return useMutation<SuccessResponse, ErrorResponse<T>, Record<T, string>>(
(data) => {
return new Promise((resolve, reject) => {
// Some logic here to either return a success or an error response
if (Math.random() > 0.5) {
resolve({
userId: "1234"
});
} else {
reject({
formErrors: [
{
field: "email", // I want TypeScript to complain if it's neither "name" nor "email"
type: "ALREADY_EXISTS"
}
]
});
}
});
}
);
};
rejectsignature, the param can't be changed. See this answer.