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

fix(vue): fix variables typing #3734

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

arkandias
Copy link
Contributor

@arkandias arkandias commented Jan 7, 2025

Summary

Background

This PR addresses issues introduced by the deep unwrapping of the variables field:

  1. Type enforcement for variables becomes extremely challenging (if not impossible)
  2. Current workarounds use type assertions that completely break the typing of variables (and maybe more)
  3. Behavior is undocumented and unintuitive for users

The proposal is to revert to simple unwrapping, along with several improvements detailed below.
Should this proposal be accepted, I'd be happy to update the documentation.

Changes

  • Revert MaybeRefObj, UseQueryArgs, and UseSubscriptionArgs definitions from d07602d
  • Align with Vue 3.3+ naming:
    • MaybeRefMaybeRefOrGetter
    • MaybeRefObjMaybeRefOrGetterObj
    • unwraptoValue
  • Replace deep unwrapping of variables (introduced in 068df71) with a simple toValue
  • Revert test changes from 068df71
  • Update 'reacts to variables changing' test to use reactive() wrapper since deep unwrapping is no longer performed
  • Regenerate pnpm-lock.yaml to use updated dependencies
  • Fix createRequest documentation

Implementation Note

In createRequestWithArgs, I had to use a type assertion for _args.variables as TypeScript struggles with type inference in this case. While the typing appears correct, I welcome review of this approach. There is also a related question on the GraphQLRequestParams definition (discussed here). Alternative suggestions for a more elegant solution are appreciated.

Discussion Point: Query Field Reactivity

While this PR doesn't modify it, I question whether the query field should support reactivity. Creating a new query via useQuery or the client handle seems more appropriate. Additionally, TypeScript users wouldn't be able to replace the query value with a different type, which arguably makes this feature useless.

Discussion Point 2: Optional Variables

As noted here, the current implementation of MaybeRefObj also breaks the behavior of GraphQLRequestParams, which makes the variables field optional in certain cases, for example for queries that do not require variables. In the definition of UseQueryArgs, the intersection with this type is wrapped in an outer MaybeRefObj:

& MaybeRefObj<GraphQLRequestParams<Data, MaybeRefObj<Variables>>>;

This causes the variables field to be non-optional even for queries that do not require variables. The reason comes from the definition of MaybeRefObj and the fact that that Exact<{ [key: string]: never; }> extends {}.

Proposed solutions

  1. Modify MaybeRefObj definition:
type MaybeRefObj<T extends {}> =
  T extends Record<string, never> ? T : { [K in keyof T]: MaybeRef<T[K]> };

This allows omitting variables when not needed while maintaining type safety, but note that other edge cases may exist.

  1. Simplify UseQueryArgs definition:
& GraphQLRequestParams<Data, MaybeRef<Variables>>;

This approach would resolve all the possible edge cases and improve type safety maintainability. It would also make the query field non-reactive, which, as I argued in the previous point, aligns with best practices.

Copy link

changeset-bot bot commented Jan 7, 2025

⚠️ No Changeset found

Latest commit: 0af324e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

- Revert the definitions of MaybeRefObj, UseQueryArgs, and UseSubscriptionArgs introduced in d07602d to resolve issue urql-graphql#3733
- Rename MaybeRef, MaybeRefObj, unwrap to MaybeRefOrGetter, MaybeRefOrGetterObj, and toValue for consistency with Vue 3.3+
- Replace deep unwrapping (introduced in 068df71) of variables with a simple toValue
- Revert test changes introduced in 068df71
- Fix 'reacts to variables changing' test by wrapping variables in reactive() since deep unwrapping is no longer performed
Rename the variables for consistency between the doc and the implementation
Add description of variable extensions
@arkandias
Copy link
Contributor Author

@JoviDeCroock Would you mind taking a look when you have a chance? Thank you!

@arkandias
Copy link
Contributor Author

Hi @JoviDeCroock, I received on email from GitHub on January 23th with a response from you, but I can't see any in this thread, did you delete it?

Just some more info (since you were concerned with the modifications to the tests): basically I reverted the test to their state before 068df71. Many of the test introduced in this commit are testing the deep unwrapping behavior, which is IMO not desirable, that's why I reverted most of it.

I'm not exactly sure how to test that type safety is working, but I can see two solutions:

  • using a dependency like tsd (which I'm not familiar with), or
  • writing .ts files which would raise errors during TS transpilation if type safety is not working; these tests would be run during tsc step, not vitest though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(vue) useQuery loses typing of variables
1 participant