Skip to content

Custom scalars cannot produce correct typings for both apollo client and server simultaneously #7272

@camjackson

Description

@camjackson

Describe the bug

When configuring custom scalars, it's not possible to have the generated types be simultaneously correct for both:

  • apollo client queries
  • apollo server resolvers

For example, with a Date scalar there are two options:

  • Date: Date:
    • ✅ This feels more semantically correct, we want to treat dates as dates
    • ✅ It works for apollo server resolvers. You can do return { someDate: new Date() } and the types work
      • (You also need to configure how apollo (de-)serialises it)
    • ❌ The type will be wrong on the client side. E.g. the generated types will incorrectly say that myQuery.data.someDate is a Date object, but it's actually a String
  • Date: String:
    • ✅ This matches how the field is serialised and sent over the network
    • ✅ It is correct on the client side, i.e. myQuery.data.someDate will be correctly typed as a string
    • ❌ The resolver type will expect you to return a string instead of a date. E.g. return { someDate: new Date() } will give a type error.

I think the root cause of this is that apollo server supports custom scalars pretty well, but apollo client doesn't support them at all. Until apollo client gets proper custom scalar support, I think that graphql-codegen should allow different types to be specified for:

  • the thing that the resolver returns; and
  • the thing that client receives

This would allow me return a date object from my resolver, and then have that come through as a string on the client.

To Reproduce

Sandbox here: https://codesandbox.io/s/intelligent-bird-pj5gj

  1. My GraphQL schema:
type Query {
    user(id: ID!): User!
}

type User {
    id: ID!
    username: String!
    email: String!
    signUpDate: Date!
}
  1. My GraphQL operations:
query user {
    user(id: 1) {
        id
        username
        email
        signUpDate
    }
}
  1. My codegen.yml config file:
schema: schema.graphql
documents: document.graphql
generates:
  types.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-resolvers
      - typescript-react-apollo
    config:
      scalars:
        Date: Date

Expected behavior

The user resolver should have signUpDate: Date in its return type, but userUserQuery should have signUpDate: String in its return type, to match the respective behaviour of apollo server and client.

Environment:

  • OS: MacOS Big Sur
  • @graphql-codegen/cli": "1.21.4"
  • @graphql-codegen/fragment-matcher": "2.0.1"
  • @graphql-codegen/introspection": "1.18.2"
  • @graphql-codegen/typescript": "1.22.0"
  • @graphql-codegen/typescript-apollo-client-helpers": "^1.1.10"
  • @graphql-codegen/typescript-operations": "1.17.16"
  • @graphql-codegen/typescript-react-apollo": "2.2.4"
  • @graphql-codegen/typescript-resolvers": "1.19.1"
  • NodeJS: 16.5.0

Additional context

Related issue: #2757

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions