-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type definitions for error
value are unknown
#483
Comments
So this was fixed in #514 - But I'm not sure this is the correct approach, since it expects errors to be This will only occur naturally by an unhandled error being thrown, and prevents you from creating custom error objects with more context. Using As an example, In my fetch function I'll reject the promise with the // See if we can get a valid JSON error message from the response.
const response = await fetch(url, request);
const json: Result = await response.json().catch(() => {
// Failed to parse a JSON response. Return an empty object instead.
return {};
});
if (response.ok) {
return json;
} else {
return Promise.reject({
status: response.status,
...json,
});
} I'd than handle the error by setting the type of the error: onError: (error: SchemaProblemDetails) => {
// In case of a 401 Unauthorized call, clear the token since it's invalid
if (error.status === 401 && clearLogin) clearLogin();
}, This will now fail, unless I do a type conversion when reading the A better way is if we can configure the expected type of error alongside the type of data. This would have the export interface BaseQueryOptions<Error = any> {
/**
* Set this to `true` to disable automatic refetching when the query mounts or changes query keys.
* To refetch the query, use the `refetch` method returned from the `useQuery` instance.
*/
manual?: boolean
/**
* If `false`, failed queries will not retry by default.
* If `true`, failed queries will retry infinitely., failureCount: num
* If set to an integer number, e.g. 3, failed queries will retry until the failed query count meets that number.
* If set to a function `(failureCount, error) => boolean` failed queries will retry until the function returns false.
*/
retry?: boolean | number | ((failureCount: number, error: Error) => boolean)
retryDelay?: (retryAttempt: number) => number
staleTime?: number
cacheTime?: number
refetchInterval?: false | number
refetchIntervalInBackground?: boolean
refetchOnWindowFocus?: boolean
refetchOnMount?: boolean
onError?: (err: Error) => void
suspense?: boolean
isDataEqual?: (oldData: unknown, newData: unknown) => boolean
} And that would than have to be passed down from the hooks, so they accept the type of error in addition to the type of result, key, variables, etc. useQuery<TResult, TKey, TError>() |
@thebuilder I am not sure if I am doing it right but it is showing me the error Object is of type 'unknown' when I try to access My code
|
You need to specify the type of the error as a generic, when creating the query. |
@thebuilder Thank you for replying. I am not that fluent with Generics can you tell me how would that work over here? I am unable to find any good resources for it. I see that the source file is typed like below but I am not sure how I would go about using this in my code.
|
You can fill out the types in side the const { status, data, error, fetchMore, canFetchMore } = useInfiniteQuery<ResultModel, Error>(
"questions",
getStackQuestions,
{
getFetchMore: (lastGroup, allGroups) => lastGroup.nextPageNumber,
staleTime: 1000 * 60 * 60 * 24 * 365,
}
);
if (status === "error") {
return <span>Error: {error.message}</span>;
} |
Do you think it might be handy to default TError = Error? I think that covers most use cases.
Problem is that TError comes after TResult which was automatically inferred, you are forcing people to define both when in an earlier version it just worked in the majority of use cases.
|
I agree with this:
|
I agree as well. It would be nice if the appropriate practice to manage this was listed in the examples. |
@thebuilder With your code example and react-query 3.6.0, I'm getting |
The most elegant solution I've found was to augment Here's example with formik's import { FormikErrors } from 'formik';
module 'react-query' {
export declare function useMutation<
TData = unknown,
TVariables = void,
TError = FormikErrors<TVariables>,
TContext = unknown
>(
mutationFn: MutationFunction<TData, TVariables>,
options?: UseMutationOptions<TData, TError, TVariables, TContext>,
): UseMutationResult<TData, TError, TVariables, TContext>;
} |
@norbertsongin it is not guaranteed that any errors you are getting are of a certain type. In JavaScript, anything can be thrown, so A real life scenario for queries would be that you have a runtime error in This is in line with TypeScripts recent change in 4.4 to default to unknown in catch clauses. relevant read: https://tkdodo.eu/blog/react-query-and-type-script#what-about-error |
I can kinda understand why the type should be Related question, if I want to manually specify useMutation<X, Error>({
queryFn: someApiFunc
})
// where X still gets inferred automatically from someApiFunc, so I don't have to duplicate ReturnType all over my code base Is this possible somehow? I can't find anything on Google about it. |
@vincerubinetti we'll change the type to be |
@TkDodo I agree with your comment that I think a win here that would help people is that inside of the const doSomething = useMutation({
mutationFn: () => {}, // do something cool
onError: (error) => {
const _error = utilityToConvertUnknownToError({
error,
context: 'Failed to move a private board',
metadata: { boards, clips, selectedBoard },
});
// typeof _error is now Error
return _error;
},
});
return (
<div>
<button onClick={doSomething.mutate}>Update</button>
{/** Since we returned a Error from `onError`, we can safely access error.message **/}
{doSomething.status === 'error' && <span>{error.message}}
</div>
} I think this still allows you to return const doSomething = useMutation<void, Error, void>(const doSomething = useMutation({
mutationFn: () => {}, // do something cool
onError: (error) => {
const _error = utilityToConvertUnknownToError({
error,
context: 'Failed to move a private board',
metadata: { boards, clips, selectedBoard },
});
// typeof _error is now Error
return _error;
},
}); Passing |
Balancing type safety with ergonomics, mostly. Defaulting to Also, the new https://tanstack.com/query/v5/docs/react/typescript#registering-a-global-error
the
this makes sure your mutation will stay in |
According to the docs, the
error
value returned by all of the hooks (useQuery
,usePaginatedQuery
,useInfiniteQuery
,useMutation
etc..) can either benull
orError
.The type definitions mostly define it as
unknown
orunknown | null
This should probably be considered with issue #475 since that issue suggests that the return value in the docs may be incorrect.
The text was updated successfully, but these errors were encountered: