Graphql-code-generator: [typescript-react-apollo] TS Error "Cannot find name 'QueryVariables'" when used with unnamed operation

Created on 3 Oct 2020  路  7Comments  路  Source: dotansimha/graphql-code-generator

Describe the bug
When I ran graphql-codegen with the following schema.json, the typescript-react-apollo plugin generates incomplete TypeScript source, saying "Cannot find name 'QueryVariables'".

By the way the following schema.json came from the "Blog" example template of AWS AppSync. I'm sure it's valid, the local GraphQL Playground works on it without errors.

To Reproduce
You can see the error in the GitHub Actions page of my reproduction repository.

https://github.com/piglovesyou/issue-example-graphql-codegen/runs/1201665757?check_suite_focus=true#step:4:34

[click] The output TypeScript source is this:

```typescript jsx import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; export type Maybe = T | null; export type Exact = { [K in keyof T]: T[K] }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: string; String: string; Boolean: boolean; Int: number; Float: number; /** The `AWSDateTime` scalar type provided by AWS AppSync, represents a valid ***extended*** [ISO 8601 DateTime](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations) string. In other words, this scalar type accepts datetime strings of the form `YYYY-MM-DDThh:mm:ss.SSSZ`. The scalar can also accept "negative years" of the form `-YYYY` which correspond to years before `0000`. For example, "**-2017-01-01T00:00Z**" and "**-9999-01-01T00:00Z**" are both valid datetime strings. The field after the two digit seconds field is a nanoseconds field. It can accept between 1 and 9 digits. So, for example, "**1970-01-01T12:00:00.2Z**", "**1970-01-01T12:00:00.277Z**" and "**1970-01-01T12:00:00.123456789Z**" are all valid datetime strings. The seconds and nanoseconds fields are optional (the seconds field must be specified if the nanoseconds field is to be used). The [time zone offset](https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators) is compulsory for this scalar. The time zone offset must either be `Z` (representing the UTC time zone) or be in the format `卤hh:mm:ss`. The seconds field in the timezone offset will be considered valid even though it is not part of the ISO 8601 standard. */ AWSDateTime: any; }; export type Query = { __typename?: 'Query'; getBlog?: Maybe; listBlogs?: Maybe; getPost?: Maybe; listPosts?: Maybe; getComment?: Maybe; listComments?: Maybe; }; export type QueryGetBlogArgs = { id: Scalars['ID']; }; export type QueryListBlogsArgs = { filter?: Maybe; limit?: Maybe; nextToken?: Maybe; }; export type QueryGetPostArgs = { id: Scalars['ID']; }; export type QueryListPostsArgs = { filter?: Maybe; limit?: Maybe; nextToken?: Maybe; }; export type QueryGetCommentArgs = { id: Scalars['ID']; }; export type QueryListCommentsArgs = { filter?: Maybe; limit?: Maybe; nextToken?: Maybe; }; export type Blog = { __typename?: 'Blog'; id: Scalars['ID']; name: Scalars['String']; posts?: Maybe; createdAt: Scalars['AWSDateTime']; updatedAt: Scalars['AWSDateTime']; }; export type BlogPostsArgs = { filter?: Maybe; sortDirection?: Maybe; limit?: Maybe; nextToken?: Maybe; }; export type ModelPostConnection = { __typename?: 'ModelPostConnection'; items?: Maybe>>; nextToken?: Maybe; }; export type Post = { __typename?: 'Post'; id: Scalars['ID']; title: Scalars['String']; blogID: Scalars['ID']; blog?: Maybe; comments?: Maybe; createdAt: Scalars['AWSDateTime']; updatedAt: Scalars['AWSDateTime']; }; export type PostCommentsArgs = { content?: Maybe; filter?: Maybe; sortDirection?: Maybe; limit?: Maybe; nextToken?: Maybe; }; export type ModelCommentConnection = { __typename?: 'ModelCommentConnection'; items?: Maybe>>; nextToken?: Maybe; }; export type Comment = { __typename?: 'Comment'; id: Scalars['ID']; postID: Scalars['ID']; post?: Maybe; content: Scalars['String']; createdAt: Scalars['AWSDateTime']; updatedAt: Scalars['AWSDateTime']; }; export type ModelStringKeyConditionInput = { eq?: Maybe; le?: Maybe; lt?: Maybe; ge?: Maybe; gt?: Maybe; between?: Maybe>>; beginsWith?: Maybe; }; export type ModelCommentFilterInput = { id?: Maybe; postID?: Maybe; content?: Maybe; and?: Maybe>>; or?: Maybe>>; not?: Maybe; }; export type ModelIdInput = { ne?: Maybe; eq?: Maybe; le?: Maybe; lt?: Maybe; ge?: Maybe; gt?: Maybe; contains?: Maybe; notContains?: Maybe; between?: Maybe>>; beginsWith?: Maybe; attributeExists?: Maybe; attributeType?: Maybe; size?: Maybe; }; export enum ModelAttributeTypes { Binary = 'binary', BinarySet = 'binarySet', Bool = 'bool', List = 'list', Map = 'map', Number = 'number', NumberSet = 'numberSet', String = 'string', StringSet = 'stringSet', Null = '_null' } export type ModelSizeInput = { ne?: Maybe; eq?: Maybe; le?: Maybe; lt?: Maybe; ge?: Maybe; gt?: Maybe; between?: Maybe>>; }; export type ModelStringInput = { ne?: Maybe; eq?: Maybe; le?: Maybe; lt?: Maybe; ge?: Maybe; gt?: Maybe; contains?: Maybe; notContains?: Maybe; between?: Maybe>>; beginsWith?: Maybe; attributeExists?: Maybe; attributeType?: Maybe; size?: Maybe; }; export enum ModelSortDirection { Asc = 'ASC', Desc = 'DESC' } export type ModelPostFilterInput = { id?: Maybe; title?: Maybe; blogID?: Maybe; and?: Maybe>>; or?: Maybe>>; not?: Maybe; }; export type ModelBlogConnection = { __typename?: 'ModelBlogConnection'; items?: Maybe>>; nextToken?: Maybe; }; export type ModelBlogFilterInput = { id?: Maybe; name?: Maybe; and?: Maybe>>; or?: Maybe>>; not?: Maybe; }; export type Mutation = { __typename?: 'Mutation'; createBlog?: Maybe; updateBlog?: Maybe; deleteBlog?: Maybe; createPost?: Maybe; updatePost?: Maybe; deletePost?: Maybe; createComment?: Maybe; updateComment?: Maybe; deleteComment?: Maybe; }; export type MutationCreateBlogArgs = { input: CreateBlogInput; condition?: Maybe; }; export type MutationUpdateBlogArgs = { input: UpdateBlogInput; condition?: Maybe; }; export type MutationDeleteBlogArgs = { input: DeleteBlogInput; condition?: Maybe; }; export type MutationCreatePostArgs = { input: CreatePostInput; condition?: Maybe; }; export type MutationUpdatePostArgs = { input: UpdatePostInput; condition?: Maybe; }; export type MutationDeletePostArgs = { input: DeletePostInput; condition?: Maybe; }; export type MutationCreateCommentArgs = { input: CreateCommentInput; condition?: Maybe; }; export type MutationUpdateCommentArgs = { input: UpdateCommentInput; condition?: Maybe; }; export type MutationDeleteCommentArgs = { input: DeleteCommentInput; condition?: Maybe; }; export type CreateBlogInput = { id?: Maybe; name: Scalars['String']; }; export type ModelBlogConditionInput = { name?: Maybe; and?: Maybe>>; or?: Maybe>>; not?: Maybe; }; export type UpdateBlogInput = { id: Scalars['ID']; name?: Maybe; }; export type DeleteBlogInput = { id?: Maybe; }; export type CreatePostInput = { id?: Maybe; title: Scalars['String']; blogID: Scalars['ID']; }; export type ModelPostConditionInput = { title?: Maybe; blogID?: Maybe; and?: Maybe>>; or?: Maybe>>; not?: Maybe; }; export type UpdatePostInput = { id: Scalars['ID']; title?: Maybe; blogID?: Maybe; }; export type DeletePostInput = { id?: Maybe; }; export type CreateCommentInput = { id?: Maybe; postID: Scalars['ID']; content: Scalars['String']; }; export type ModelCommentConditionInput = { postID?: Maybe; content?: Maybe; and?: Maybe>>; or?: Maybe>>; not?: Maybe; }; export type UpdateCommentInput = { id: Scalars['ID']; postID?: Maybe; content?: Maybe; }; export type DeleteCommentInput = { id?: Maybe; }; export type Subscription = { __typename?: 'Subscription'; onCreateBlog?: Maybe; onUpdateBlog?: Maybe; onDeleteBlog?: Maybe; onCreatePost?: Maybe; onUpdatePost?: Maybe; onDeletePost?: Maybe; onCreateComment?: Maybe; onUpdateComment?: Maybe; onDeleteComment?: Maybe; }; export type ModelIntInput = { ne?: Maybe; eq?: Maybe; le?: Maybe; lt?: Maybe; ge?: Maybe; gt?: Maybe; between?: Maybe>>; attributeExists?: Maybe; attributeType?: Maybe; }; export type ModelFloatInput = { ne?: Maybe; eq?: Maybe; le?: Maybe; lt?: Maybe; ge?: Maybe; gt?: Maybe; between?: Maybe>>; attributeExists?: Maybe; attributeType?: Maybe; }; export type ModelBooleanInput = { ne?: Maybe; eq?: Maybe; attributeExists?: Maybe; attributeType?: Maybe; }; export type Unnamed_1_QueryVariables = Exact<{ filter?: Maybe; limit?: Maybe; nextToken?: Maybe; }>; export type Unnamed_1_Query = ( { __typename?: 'Query' } & { listBlogs?: Maybe<( { __typename?: 'ModelBlogConnection' } & { items?: Maybe )>>> } )> } ); export const Document = gql` query ($filter: ModelBlogFilterInput, $limit: Int, $nextToken: String) { listBlogs(filter: $filter, limit: $limit, nextToken: $nextToken) { items { id } } } `; /** * __useQuery__ * * To run a query within a React component, call `useQuery` and pass it any options that fit your needs. * When your component renders, `useQuery` returns an object from Apollo Client that contains loading, error, and data properties * you can use to render your UI. * * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example * const { data, loading, error } = useQuery({ * variables: { * filter: // value for 'filter' * limit: // value for 'limit' * nextToken: // value for 'nextToken' * }, * }); */ export function useQuery(baseOptions?: Apollo.QueryHookOptions) { return Apollo.useQuery(Document, baseOptions); } export function useLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { return Apollo.useLazyQuery(Document, baseOptions); } export type QueryHookResult = ReturnType; export type LazyQueryHookResult = ReturnType; export type QueryResult = Apollo.QueryResult; ```

You can see the QueryVariables is not declared.

  1. My GraphQL schema:

https://github.com/piglovesyou/issue-example-graphql-codegen/blob/master/schema.json

  1. My GraphQL operations:

https://github.com/piglovesyou/issue-example-graphql-codegen/blob/master/listBlogs.graphql

  1. My codegen.yml config file:

https://github.com/piglovesyou/issue-example-graphql-codegen/blob/master/codegen.yml

Expected behavior
It should generate a valid TypeScript source.

Environment:

  • OS: macOS 10.15.6
  • @graphql-codegen/typescript-react-apollo:
  • NodeJS: 0.14.x, 0.12.x
bug plugins

Most helpful comment

I recommend naming too. But if another developer forgets to write a name then they get this obscure message that is very difficult to figure out.

Could we show a warning?

All 7 comments

Does it work when you name the query?

Oh, it turns out yes.

Ran into this too. Can we make it ignore them instead of causing this error?

@vjpr we were ignoring this before, and then there was too many requests to make it available because other plugins needs it. I recommend naming your operations, regardless of this issue, it's helpful for caching purposes, and have an overview of what your operation does.

I recommend naming too. But if another developer forgets to write a name then they get this obscure message that is very difficult to figure out.

Could we show a warning?

@vjpr i'm all in with that ;) PRs are welcome. Should be pretty simple to implement.
If you wish to have a better workflow, you can try this: https://github.com/dotansimha/graphql-eslint ;)

FYI for anybody searching for this in the future: I ran into the same issue with an unnamed mutation: Cannot find name 'MutationVariables'

Adding a name to the mutation fixed the tsc issue.

Was this page helpful?
0 / 5 - 0 ratings