Skip to content
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

feat: type-safe way to skip/disable useQuery #4252

Closed
1 task
maxkostow opened this issue Apr 25, 2023 · 5 comments
Closed
1 task

feat: type-safe way to skip/disable useQuery #4252

maxkostow opened this issue Apr 25, 2023 · 5 comments

Comments

@maxkostow
Copy link

maxkostow commented Apr 25, 2023

Describe the feature you'd like to request

It would be useful to be able to skip a query in a type-safe way.

Currently, using the enabled option will cause type-checking to fail like

const param: string | null

// only want to run the query if param is defined
const result = trpc.endpoint.useQuery(
  { param }, // will fail type-checking if param must be a string
  { enabled: !!param }
)

Describe the solution you'd like to see

rtk-query has the concept of a skipToken on their useQuery which is a special object that allows the input arg to pass the type checking and disables the query (docs link).

import { skipToken } from '@trpc/react-query'

const param: string | null

// only want to run the query if param is defined
const result = trpc.endpoint.useQuery(
  param ? { param } : skipToken
)

Describe alternate solutions

Some alternate solutions

  • Use any to bypass type-checking - requires keeping both args in sync
const NULL_AS_ANY = null as any
const param: string | null

// only want to run the query if param is defined
const result = trpc.endpoint.useQuery(
  param ? { param } : NULL_AS_ANY, // passes type-checking but requires keeping both args in sync
  { enabled: !!param }
)
  • Lower the query - additional boilerplate and potentially undesirable decomposition of component
param ? <MakeTheQuery param={param} /> : <DoNotMakeTheQuery />
  • use useQueries - not the most ergonomic and seems to be discouraged
const results = trpc.useQueries(t => param ? [t.endpoint.query({ param })] : [])
const result = results.length ? results[0] : null // variable type

Additional information

Discord discussion: https://discord.com/channels/867764511159091230/1100458301281550457/1100458301281550457

👨‍👧‍👦 Contributing

  • 🙋‍♂️ Yes, I'd be down to file a PR implementing this feature!
@Nick-Lucas
Copy link
Contributor

The solutions you’ve come up with are correct. If you think there’s a better way you should raise it with the react-query GitHub because we just wrap it and don’t add additional functionality which they don’t already provide

@Nick-Lucas Nick-Lucas closed this as not planned Won't fix, can't repro, duplicate, stale Apr 25, 2023
@maxkostow
Copy link
Author

maxkostow commented Apr 25, 2023

I believe this is an issue with how tRPC abstracts the react-query API by asserting the type of the input param for disabled queries.

A raw react-query example could use the lack of ts array bounds checking which still has the issue of duplicating the check but does not have to use the any type or an assertion

const param: string | null

useQuery({
  queryKey: param ? [param] : [],
  queryFn: ({ queryKey }) => fetchSomething(queryKey[0]),
  enabled: !!param
})

@Nick-Lucas
Copy link
Contributor

Typescript has no idea at compile time whether a procedure is enabled or disabled, because that is assumed to be changing at run-time. Therefore there is no way to validate that the variables being passed to the input are valid at compile time either.

The input won't be used when disabled, so either it has to be faked with some dummy/placeholder data or a any type (which won't be used by RQ) or the type definition of the input has to be MyType | null and you pass null in that instance, but that possible null will also need handling by your procedure in the API.

There's nothing AFAIK which tRPC can do here, it's an application choice of how to work within the type system.

If you have a strong belief it can be improved then PRs are welcome of course 🙂

@maxkostow
Copy link
Author

I am not a typescript expert, but I wonder if it would be possible to do something like

interface IUseQuery<Input, Options, Output> {
  (input: Options extends { enabled: false } ? unknown : Input, options: Options): Output
}

@KATT
Copy link
Member

KATT commented Apr 26, 2023

Not possible in a nice way AFAIK.

The underlying reason is that React doesn't support conditional hooks.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants