I have a React component that looks like this (highly simplified code):
const TestComponent = () => {
const { data: stuff, isLoading: isLoadingStuff, isSuccess: hasLoadedStuff } = useStuff();
// ... other similar RQ query wrapper hooks
const isLoading = isLoadingStuff && isLoadingOtherStuff;
const loaded = hasLoadedStuff && hasLoadedOtherStuff;
return (
<div>
<Loading isLoading={isLoading} />
{loaded && (
<Stuff stuff={stuff} />
<OtherStuff otherStuff={otherStuff} />
)}
</div>
)
}
I have a number of RQ queries wrapped in custom hooks (like useStuff
). For increased readability I have extracted and renamed the values I’m interested in using object destructuring. However TS doesn’t seem to be able to infer that if loading === true
then stuff
cannot be undefined
and so I get the following error for stuff={stuff}
:
TS2322: Type string[] | undefined is not assignable to type string[]
Type undefined is not assignable to type string[]
Of course if I revert to
const stuff = useStuff();
const isLoading = stuff.isLoading && otherStuff.isLoading
// and then
<Stuff stuff={stuff.data} />
then it works fine.
Is there a way around this or must I resign myself to the second approach?
Many thanks!
2
Answers
You just need to add a discriminated union as the return type of your hooks. In recent versions, typescript can follow discriminated unions though both destructuring and indirection (if assigned to const variables)
Playground Link
check this playground. i recreated your example and it works fine, but you need to use discriminated union types in your hook implementation.
maybe you are not running the latest typescript version? this type of tracking and inference was introduced not long ago.