redux-toolkit
redux-toolkit copied to clipboard
"Types of property 'isUninitialized' are incompatible." when extending a useQuery hook
I'm trying to extend a useQuery() hook with the newly released TypedUseQueryHookResult type introduced in 1.8.4, but I'm getting the following:
Types of property 'isUninitialized' are incompatible.
Type 'true' is not assignable to type 'false'.ts(2322)
The code (with CodeSandbox):
import {
createApi,
fetchBaseQuery,
TypedUseQueryHookResult
} from "@reduxjs/toolkit/query/react";
type MyApiProps = {
id: string;
};
type MyApiResponse = Array<{
id: string;
name: string;
}>;
export const api = createApi({
reducerPath: "myApi",
baseQuery: fetchBaseQuery({ baseUrl: "https://some-api.com/api/v1" }),
tagTypes: ["MyApi"],
endpoints: (build) => ({
getData: build.query<MyApiResponse, MyApiProps>({
query: ({ id }) => `my-api/${id}`
})
})
});
export const useGetData = (
args: MyApiProps
): TypedUseQueryHookResult<
MyApiResponse,
MyApiProps,
ReturnType<typeof fetchBaseQuery>
> =>
api.useGetDataQuery(args, {
selectFromResult: (results) => ({
...results,
data: results.data?.filter((d) => d.name === "Harry")
})
});
Note that this usage of selectFromResult() works just fine if I use the auto-generated hook directly in a component.
Weird enough, if you declare the return type like
export const useGetData = (
args: MyApiProps
): Omit<
TypedUseQueryHookResult<
MyApiResponse,
MyApiProps,
ReturnType<typeof fetchBaseQuery>
>,
""
>
so essentially omitting a property that does not exist - everything works :thinking:
Most likely Omit works because it "downgrades" the union to an object type as Omit is not distributive.
I took a quick look with the debugger there, and I think I got good information to help you solve this. If we Compute every member of those unions etc then we can reason about this way easier: TS playground. You can see that the reported error is essentially the same here.
We can also sort all keys everywhere to make comparisons easier, but that changes the reported error (which is fine, it's just order-dependant): TS playground
We can also remove all but first types in the ExprType union because as far I've seen in the debugger it's already the first member of that union that doesn't match: TS playground
Then we can drop the fourth element of the RetType because it clearly can't be matched based on the currentType: TS playground
Then we can drop 2 first members of that RetType union too, because data property doesn't match: TS playground
And now we can conclude that those are not available at least because the error property is required in one of those union members of the TypedUseQueryHookResult (even though it's value is undefined) but it's optional in the UseQueryHookResult. This is defined on the third union member of the TypedUseQueryHookResult but the order in the union is not guaranteed so perhaps we shouldn't rely on this - it's likely that this matches the definition order though.
I think I've chosen a slight detour here, in this reasoning, because the easiest would be to just name all of the union members, like here. And then to compare them one by one with the ExprType - this allows us quickly to check if the reported error matches what we were seeing in the app~ or not. Based on that we can see that isUninitialized: true; is only in one of the union members of the TypedUseQueryHookResult so it's the only potential candidate from this PoV BUT at the same time its data property doesn't match the property type in the slimmed down UseQueryHookResult (we can't assign something to what expect undefined).
TLDR: there are a couple of assignability problems here.