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

Allow to pass generics to DocumentNode to allow TS type inference by GraphQL clients #2728

Closed
wants to merge 2 commits into from
Closed

Allow to pass generics to DocumentNode to allow TS type inference by GraphQL clients #2728

wants to merge 2 commits into from

Conversation

dotansimha
Copy link
Member

Resolves #2727

@dotansimha
Copy link
Member Author

Hi @IvanGoncharov , @leebyron how can we progress with this one? thanks!

Copy link
Member

@IvanGoncharov IvanGoncharov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm totally for adding wrapping type for DocumentNode.
But It should be a separate type since the template argument is never used in DocumentNode or any other node. Plus DocumentNode can also contain SDL definitions.
So it should be separate type inherited from DocumentNode e.g. TypedQueryDocumentNode or something similar.

But I'm fully against changes to graphql/execute:

  1. We shouldn't provide typings for something we can't guarantee. For example, we plan to merge @defer that will change payload and it would be different from type generated by graphql-codegen. The same goes for other custom directives that change payload or custom scalars that have representation other that string.
  2. What are production use cases for typing the result of execute/graphql? Client queries are sent over the wire and we don't have type info on the server. I understand how typed queries are helpful on the client but I struggle to understand why it's needed on the server.

Summary: I understand how useful it would be to bind type info to query and share it between other tools so I'm fully for adding this type. However, I strongly disagree with reference implementation providing typings for execute/graphql that it can't guarantee to be in sync with what is actually returned.

@dotansimha
Copy link
Member Author

dotansimha commented Aug 16, 2020

Thank you @IvanGoncharov for the review!

@ForbesLindesay suggested (dotansimha/graphql-typed-document-node#34) to add internal types to DocumentNode to make sure TypeScript treats it as structural type and not removing the generics because they are unused.

Regarding execute/graphql functions:

  1. Type inference won't work without adding the generics to the entire chain of calls. If execute won't have the generics, it won't get inferred later based on DocumentNode passed to it.
  2. I do understand how @defer could effect it, but just like @skip and @include - this effect types only, and probably just make it optional.
  3. graphql-codegen will handle the @defer when it will be available in graphql-js and will allow developers to reflect the effect of it on generated types. But please note that graphql-codegen isn't the only way to use generate types. Developers can manually specify the types.
  4. No one expects GraphQL to be responsible for the result and match the generic types. If you allow to pass generics - developers knows that he's in charge of those types, and it's not part of the package itself.
  5. We don't have to change execute / graphql at all if you wish, but then it will mean that only tools that uses DocumentNode will benefit from the inferred types. Also, graphql-js is used by many projects locally, and execute sometimes is being executed directly with an operation that has been declared locally.

@IvanGoncharov what do you think about the following: I can remove all the changes from execute, graphql and even from Source and limit those changes only for DocumentNode to allow generics in it. These will be defaulted to any / record value in order to make sure it's not breaking anything.
That means that types could still be inferred while DocumentNode is being used by other libraries / graphql clients.

I don't think adding a new type called TypedDocumentNode will be the best solution, because then it means we do need to change execute and others to allow DocumentNode | TypedDocumentNode.

@dotansimha
Copy link
Member Author

@IvanGoncharov I updated the PR with the minimal changes possible, in order to support that. What do you think?

@dotansimha dotansimha changed the title Allow to pass generics to Source and DocumentNode to allow TS type inference Allow to pass generics to DocumentNode to allow TS type inference by GraphQL clients Aug 16, 2020
@IvanGoncharov
Copy link
Member

@dotansimha Thanks 👍
As I wrote above can we add separate TypedQueryDocumentNode type with template parameters inherited from DocumentNode?

@dotansimha
Copy link
Member Author

Thanks @IvanGoncharov .
As It wrote before, I think making it a new variable might make it more difficult to adopt in GraphQL client libraries. Since it means they need to modify the codebase to use TypedDocumentNode instead of the original DocumentNode.

Are you open to keep it as part of the original DocumentNode? it doesn't break anything, and it fully compatible.

@IvanGoncharov
Copy link
Member

As It wrote before, I think making it a new variable might make it more difficult to adopt in GraphQL client libraries.

@dotansimha Sorry missed that in you previous comment.

I don't think adding a new type called TypedDocumentNode will be the best solution, because then it means we do need to change execute and others to allow DocumentNode | TypedDocumentNode.

Here is a snippet that execute should work perfectly fine with a new type and it also shows how to implement wrapper function around execute that utilize full potential of this new type:

interface DocumentNode {
  someValue: number
}


interface TypedDocumentNode<TArg> extends DocumentNode {
}

function execute(document: DocumentNode): unknown { return null; }

const stringTypedDocume...

Playground Link

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.

Allow result type and variables type to be inferred from DocumentNode/Source using TypeScript type system
2 participants