graphql-code-generator-community icon indicating copy to clipboard operation
graphql-code-generator-community copied to clipboard

react-query plugin with graphql-request fetcher generates invalid infinite query if query has no arguments

Open iscekic opened this issue 3 years ago • 9 comments

Describe the bug

The latest version introduces an issue where, if an infinite query has no arguments, the react-query plugin generates invalid types.

Your Example Website or App

/

Steps to Reproduce the Bug or Issue

  1. write a query without arguments
  2. observe type error in generated code

The error comes from the 3rd argument passed to fetcher:

error TS2345: Argument of type '{ [x: string]: any; }' is not assignable to parameter of type 'Exact<{ [key: string]: never; }>'.
  'string' index signatures are incompatible.
    Type 'any' is not assignable to type 'never'.

Expected behavior

No error.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • NodeJS: 16.7.1
  • graphql version: 16.6.0
    "@graphql-codegen/cli": "^2.13.7",
    "@graphql-codegen/typescript": "^2.8.0",
    "@graphql-codegen/typescript-graphql-request": "^4.5.7",
    "@graphql-codegen/typescript-operations": "^2.5.5",
    "@graphql-codegen/typescript-react-query": "^4.0.3",

Codegen Config File

scalars omitted to keep it short

overwrite: true
generates:
  src/modules/common/generated/client.graphql.ts:
    documents: "src/**/*.graphql"
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-query"
    config:
      dedupeFragments: true
      immutableTypes: true
      skipTypename: true
      maybeValue: T | null | undefined
      namingConvention:
        enumValues: keep
        typeNames: keep
      strictScalars: true
      fetcher: graphql-request
      exposeQueryKeys: true
      addInfiniteQuery: true

Additional context

Only happens in latest version.

iscekic avatar Oct 24 '22 10:10 iscekic

This is on my radar. The last hotfix fixed one subset of issues, but not this one.

I believe the issue stems from trying to unpack metaData.PageParam when it exists into the variables if the infiniteQuery call has no variables.

It's a bit unclear to me how the pagination occurs for these calls if they accept no variables. My understanding is this only happens for calls where no pagination occurs anyways (single-object response GET calls, etc.). So ideally, you wouldn't want gql-codegen to generate infiniteQuery hooks for these calls to begin with since they're never used.

Short of that, I'll explore conditionally unpacking metaData.pageParam for hooks where variables exist (and therefore pagination could be present).

EandrewJones avatar Nov 10 '22 17:11 EandrewJones

So ideally, you wouldn't want gql-codegen to generate infiniteQuery hooks for these calls to begin with since they're never used.

It would be cool to have some sort of macro system where a comment in a graphql file could tell codgen to skip generating an infinite query for a specific query (or more likely, to indicate that an infinite query should be generated)

wileymc avatar Nov 10 '22 18:11 wileymc

So ideally, you wouldn't want gql-codegen to generate infiniteQuery hooks for these calls to begin with since they're never used.

This is correct. My setup is "all queries in one file", which is why the issue occurs.

If a fix lands where I can keep my current setup, great, otherwise I'll probably end up moving the problematic queries to a separate file and setting addInfiniteQuery: false

iscekic avatar Nov 14 '22 07:11 iscekic

How can you set config like addInfiniteQuery: false for a specific subset of .graphql files?

wileymc avatar Nov 19 '22 06:11 wileymc

Sorry for the delay on this folks. I promise I'm going to spend time on the fix tomorrow.

I doubt it'll involve adding a new parameter to the config file to specify which queries have infiniteQuery generated for them (though that type of fine grained control would be cool). I think some simple type checking and conditional statements will suffice.

On Sat, Nov 19, 2022, 1:55 AM Wiley McKay Conte @.***> wrote:

How can you set config like addInfiniteQuery: false for a specific subset of .graphql files?

— Reply to this email directly, view it on GitHub https://github.com/dotansimha/graphql-code-generator-community/issues/227, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJ2T6ANPFNQWZ6WS264JH4LWJB2VHANCNFSM6AAAAAARM2FP6A . You are receiving this because you commented.Message ID: @.***>

EandrewJones avatar Nov 19 '22 08:11 EandrewJones

Does anyone have a nice workaround for this problem?

nzbart avatar Apr 12 '23 19:04 nzbart

Does anyone have a nice workaround for this problem?

I ended up setting addInfiniteQuery to false in my config and manually writing a few custom useInfiniteQuery hooks where needed. Worked well for me, but only have a few infinite queries

wileymc avatar Apr 13 '23 15:04 wileymc

Hi guys, I have came up with a work around without manually set individual query. In our team we use custom fetcher, and originaly with type like bellow:

type CustomFetcher = <TData, TVariables>(
  query: string,
  variables?: TVariables,
  options?: any,
) => () => Promise<TData>;

Not surprise we encountered this issue:

error TS2345: Argument of type '{ [x: string]: any; }' is not assignable to parameter of type 'Exact<{ [key: string]: never; }>'.
  'string' index signatures are incompatible.
    Type 'any' is not assignable to type 'never'.

Then we fixed it with ts conditional types:

type CustomFetcher = <TData, TVariables>(
  query: string,
  variables?: TVariables extends { [x: string]: never }
    ? { [x: string]: any }
    : TVariables,
  options?: any,
) => () => Promise<TData>;

Just modify the interface let our type can conditionally switch to any when it detect never.

neil585456525 avatar May 24 '23 04:05 neil585456525

Hi guys, I have came up with a work around without manually set individual query. In our team we use custom fetcher, and originaly with type like bellow:

type CustomFetcher = <TData, TVariables>(
  query: string,
  variables?: TVariables,
  options?: any,
) => () => Promise<TData>;

Not surprise we encountered this issue:

error TS2345: Argument of type '{ [x: string]: any; }' is not assignable to parameter of type 'Exact<{ [key: string]: never; }>'.
  'string' index signatures are incompatible.
    Type 'any' is not assignable to type 'never'.

Then we fixed it with ts conditional types:

type CustomFetcher = <TData, TVariables>(
  query: string,
  variables?: TVariables extends { [x: string]: never }
    ? { [x: string]: any }
    : TVariables,
  options?: any,
) => () => Promise<TData>;

Just modify the interface let our type can conditionally switch to any when it detect never.

God bless you and God bless Typescript :)

saalihou avatar Feb 01 '24 12:02 saalihou