DamianOsipiuk / vue-query

Hooks for fetching, caching and updating asynchronous data in Vue
https://vue-query.vercel.app/
MIT License
1.11k stars 48 forks source link

Help typing composables query #224

Closed Vincent-HD closed 2 years ago

Vincent-HD commented 2 years ago

Hi, I'm having troubles when typing a composable for a query. I have an axios endpoint which need a number to be a valid call image Then I made this composable for the query which work well like that image

But the value passed in useQueryGetAttachmenInfo() can be a number or false (normally false is impossible because the query depends on another query) image Code_Wgkodvvv0q

But if I type guard the call of useQueryGetAttachmenInfo() cg_recto != false it will be never called because at first it's always false (because it will be enabled by another query)

Other question : I've also not be able to correctly type the options field that can be passed in useQueryGetAttachmenInfo()(by example to pass enabled computed) Code_SKUVj3vWJV I can infer the type with vscode but it's a very long type, and I don't feel that's a good way to do it

DamianOsipiuk commented 2 years ago

Hi, So the first problem could be soled by always providing a number to the function ex. cg_recto || 0 In addition to that you can use enabled option to control when query should be run. IE when you actually get a number instead of false.

The second problem is that in v1 the Query key signature is export type QueryKey = string | readonly unknown[]

Which means that you cannot pass number as query key. Ideally you should use an array for easier migration to v2

Vincent-HD commented 2 years ago

First thanks you for your answer, I really do appreciate it.

So the first problem could be soled by always providing a number to the function ex. cg_recto || 0

Yep, I should of thought about it, I just need to properly type it because it wants a computed value.

In addition to that you can use enabled option to control when query should be run. IE when you actually get a number instead of false.

Yes I was planning to do so as you can see with cg_rectoEnabled, but since I didn't achieve to properly typed options parameter of my composable, I didn't pass the value to it, it would of added the enable option like that: Code_pubVfTJ6W3

But it is not supposed to know that since enabled is provided (so it needs the response of another query, or at least a value to be set via the computed) then it's impossible for the useQuery to receive something other than a number ? Or it's impossible to do so with Typescript typing ? What I mean by that, is that is it possible for Typescript to understand the meaning of enabled ? Like it's requiring the appropriate value to be able to fetch the query.

The second problem is that in v1 the Query key signature is export type QueryKey = string | readonly unknown[]

Which means that you cannot pass number as query key. Ideally you should use an array for easier migration to v2

I'm unsure of what you meant, first off I didn't know that v2 has released, so I will look into it, but it seems that the only major difference is that queryKey needs be an array, so it would quite easy to migrate, which is a good thing 👍

I achieved to "solve" the problem by typing UseQueryOptions and useQuery like that: Code_iVYqneejXt

I'm not sure to properly understanding why and if it's a good solution, I'm starting with Typescript and "advanced" typing like that is kinda difficult to apprehend

DamianOsipiuk commented 2 years ago

So i see a couple of problems here.

First i think that you should narrow down the options object of your custom hook, to only the things that you actually need. Then your signature could look like:

useQueryGetAttachementInfo(attachement_id: Ref<number | undefined> | number, options: { enabled: Ref<boolean>})

Another thing is that in your code options is optional, but then you try to spread it. It will throw an error when you try to run ...undefined. With spread you should actually default it to an empty object.

Last thing is that when you add manual type to useQuery, you can actually loose some type inference. Ideally it should be automatically inferred from the return type of the fetcher function. You can read more about it here: https://tkdodo.eu/blog/react-query-and-type-script

DamianOsipiuk commented 2 years ago

Feel free to reopen the issue if you have more questions.