You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I’ve been rethinking error handling in TypeScript.
In TypeScript, throwing errors causes the error type to be unknown. To refine it, we need instanceof checks or type guards, but we don’t get type safety for domain-specific error values.
Libraries like Effect and neverthrow use this to provide type safety and better error modeling.
The Problem
To make this work with TanStack Query today, we need to do something like:
queryFn: async()=>{constresponse=awaitclientApi.GET("/api");if(response.data==null){throwresponse.error;// loses type information}returnresponse.data;},
This allows onError to catch errors, but we lose type information about what those errors are.
If we instead return errors as part of the queryFn:
we preserve type safety, but the code becomes misleading (errors look like successes).
constquery=useQuery({
queryFn
})if(query.isSuccess){if(query.data.error!=null){// handle typed query.data.data}else{// handle typed query.data.error}}if(query.isError){// handle query.error in type Error (unknown error)}}
It also risks breaking built-in mechanisms like retries and suspense - because the call looks like a success but it failed internall.
What I’d Like
As a user, I want to express my code in terms of success and failure while retaining type safety for known errors.
I would like to introcude the distinction between a success API that returns error, and success API that returns success data and API failure. Maybe we can create a function that will tell tanstack query how to extract the error / data from the success data, and will pipe the data to data, error and defect (current tanstack error)
We can add a function like extractSuccessValue<T, E>: (value: T | E) => T | null that can somehow split the success value that contains error to a differect value / callback.
constquery=useQuery({queryFn: async(): Promise<Result<string[],{code: "NotFound"|"Unauthorized"}>>=>{returnawaitclient.GET("/api");},},extractSuccessValue: (value: Result<string[],{code: "NotFound"|"Unauthorized"}>)=>value.data// hopefully this will help narrowing the success value to string[]);// Usageif(query.error){// narrowed to { code: "NotFound" | "Unauthorized" }}if(query.defect){// regular runtime Error}if(query.data){// string[]}
I'm not sure the current suggestion of my implementation is possible due to typescipt limitation, but I think we can somehow split between success values and errors with type-safety. Let me know what do you think
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Background
I’ve been rethinking error handling in TypeScript.
In TypeScript, throwing errors causes the error type to be
unknown
. To refine it, we needinstanceof
checks or type guards, but we don’t get type safety for domain-specific error values.A common alternative is the Result pattern:
Libraries like Effect and neverthrow use this to provide type safety and better error modeling.
The Problem
To make this work with TanStack Query today, we need to do something like:
This allows
onError
to catch errors, but we lose type information about what those errors are.If we instead return errors as part of the
queryFn
:we preserve type safety, but the code becomes misleading (errors look like successes).
It also risks breaking built-in mechanisms like retries and suspense - because the call looks like a success but it failed internall.
What I’d Like
As a user, I want to express my code in terms of success and failure while retaining type safety for known errors.
I would like to introcude the distinction between a success API that returns error, and success API that returns success data and API failure. Maybe we can create a function that will tell tanstack query how to extract the error / data from the success data, and will pipe the data to
data
,error
anddefect
(current tanstack error)We can add a function like
extractSuccessValue<T, E>: (value: T | E) => T | null
that can somehow split the success value that contains error to a differect value / callback.I'm not sure the current suggestion of my implementation is possible due to typescipt limitation, but I think we can somehow split between success values and errors with type-safety. Let me know what do you think
Beta Was this translation helpful? Give feedback.
All reactions