urql
urql copied to clipboard
QueryArgs `variables` type seems to be broken with TypedDocumentNode
Describe the bug
There is a Typescript error thrown by the variables
argument in the following minimal example:
function example<Result, Variables>(
query: TypedDocumentNode<Result, Variables>,
variables: Variables,
) {
return useQuery({ query, variables });
}
The reproduction provided shows the same error with React, Vue, and Svelte implementations (press "Run" in the REPL to see the tsc output).
I would submit a PR but I'm not sure of the use cases you're trying to cover with the type definition. Apologies if this is a misunderstanding on my end!
Reproduction
https://replit.com/@jaschaephraim/Urql-Variables-Example#index.ts
Urql version
urql v3.0.2 @urql/vue v1.0.2 @urql/svelte v3.0.1
Validations
- [X] I can confirm that this is a bug report, and not a feature request, RFC, question, or discussion, for which GitHub Discussions should be used
- [X] Read the docs.
- [X] Follow our Code of Conduct
The linked reproduction in question does not compile as per the stated error message because the generics you're passing are not compatible anymore in the new major.
The exact generic is shown here for instance: https://github.com/FormidableLabs/urql/blob/0582f9b138ddb66c5164b00a978aac90e865c0dc/packages/core/src/client.ts#L101-L105
This means that your generic has to be bound now by AnyVariables
, e.g. <Variables extends AnyVariables>
. Afterwards, the generic will match but some bindings will then have problems interpreting the type to be matching. That's because depending on what kind of generic is actually passed the argument becomes "empty" or not. In other words, because some queries allow for optional or no variables sometimes undefined
or {}
is allowed and sometimes not, but you can basically at that point just cast your options, e.g.:
export function react<Result, Variables extends AnyVariables>(
query: TypedDocumentNode<Result, Variables>,
variables: Variables,
) {
return useQueryReact(
{ query, variables } as UseQueryArgs<Result, Variables>
);
}
I think the reason that worked is because the REPL was using an old version of TypeScript (v4.4.4). Starting with the following version the casting no longer works. Here's an updated example using the current version of TypeScript (v4.8.4):
https://replit.com/@jaschaephraim/Urql-Variables-Example-Latest-TS#index.ts
Hiya :wave: I'm planning to still look into this before we release the next set of patches. I'm sure there should be a way around this or an escape hatch we can make more obvious around these new typings.
I believe I have the same issue.
I have a function that wraps queryStore
from @urql/svelte
. I cannot find a generic type that will satisfy the new definition of variables
in QueryArgs. It works just fine when passing a concrete type, but when I attempt to accept AnyVariables
in my function signature, just like queryStore
does, I get an error:
Type '{ query: string | DocumentNode | TypedDocumentNode<Data, Variables>; client: Client; requestPolicy: RequestPolicy | undefined; }' is not assignable to type 'QueryArgs<Data, Variables>'. Type '{ query: string | DocumentNode | TypedDocumentNode<Data, Variables>; client: Client; requestPolicy: RequestPolicy | undefined; }' is not assignable to type 'Variables extends void ? { variables?: Variables | undefined; } : Variables extends { [P in keyof Variables]: Variables[P] | null; } ? { ...; } : { ...; }'.ts(2322)
Here is my function:
export async function storePromise<Data = any, Variables extends AnyVariables = AnyVariables>(query: string | DocumentNode | TypedDocumentNode<Data, Variables>, variables: Variables, client: Client, requestPolicy: RequestPolicy|undefined): Promise<ReturnType<typeof queryStore<Data, Variables>>> {
return new Promise((resolve, reject) => {
// Next line errors:
const qargs: QueryArgs<Data, Variables> = {query, client, requestPolicy}
const s = queryStore<Data, Variables>(qargs)
const unsubscribe = s.subscribe(value => {
if (!value.fetching || value.error) {
resolve(s)
}
})
// Some other code...
})
}
Hiya, sorry to drop the ball here for a bit! :wave: It took me a little to realise and identify when this would occur and which cases we forgot.
@jaschaephraim: Thanks for the reproduction! By the way, UseQueryArgsReact<Result, Variables>
should read UseQueryArgsReact<Variables, Result>
instead there. That's because the generics there are swapped to not break backwards compatibility.
Anyway! #3022 should be resolving these problems.
@freb: This should also start working; That said, this is an extremely convoluted way to do this, if that's how you're trying to get to a promise, since this is a thing 😅 https://formidable.com/open-source/urql/docs/basics/core/#one-off-queries-and-mutations