Graphql-code-generator: can't use __typename inside async function

Created on 9 Mar 2020  Â·  8Comments  Â·  Source: dotansimha/graphql-code-generator

Describe the bug
I get Type error when I try to use __typename inside async function

  1. this work fine
const signInWithEmail: MutationResolvers["signInWithEmail"] = () => {
    return {
        __typename: "LoginResponse",
        token: "token"
    }
}

but here when I add async I get the error

const signInWithEmail: MutationResolvers["signInWithEmail"] = async () => {
    return {
        __typename: "LoginResponse",
        token: "token"
    }
}

The error

TS2322: Type '() => Promise<{ __typename: string; token: string; }>' is not assignable to type 'ResolverFn<LoginResponse | UserError | Promise<LoginResponse> | Promise<UserError>, {}, any, RequireFields<MutationSignInWithEmailArgs, "input">> | StitchingResolver<...> | undefined'.
   Type '() => Promise<{ __typename: string; token: string; }>' is not assignable to type 'ResolverFn<LoginResponse | UserError | Promise<LoginResponse> | Promise<UserError>, {}, any, RequireFields<MutationSignInWithEmailArgs, "input">>'.
     Type 'Promise<{ __typename: string; token: string; }>' is not assignable to type 'LoginResponse | UserError | Promise<LoginResponse> | Promise<UserError> | Promise<LoginResponse | UserError | Promise<...> | Promise<...>>'.
       Type 'Promise<{ __typename: string; token: string; }>' is not assignable to type 'Promise<LoginResponse>'. 
         Type '{ __typename: string; token: string; }' is not assignable to type 'LoginResponse'.
           Types of property '__typename' are incompatible.
             Type 'string' is not assignable to type '"LoginResponse" | undefined'.
  1. My GraphQL schema:
    input SignInInfo {
        email: String!
        password: String!
    }
    type LoginResponse {
        token: String!
    }

    union SignInResult = LoginResponse | UserError

    type Mutation {
        signInWithEmail(input: SignInInfo!): SignInResult!
    }

    type UserError {
        message: String!
    }
  1. My codegen.yml config file:
overwrite: true
schema: "http://localhost:4000/"

documents: null
generates:
  src/generated/graphql.ts:
    plugins:
      - "typescript"
      - "typescript-resolvers"
    config:
      useIndexSignature: true

Expected behavior

Environment:

  • OS: Ubuntu 19.10
  • "@graphql-codegen/cli": "^1.12.2"
  • "@graphql-codegen/typescript": "1.12.2"
  • "@graphql-codegen/typescript-resolvers": "^1.12.2"
  • NodeJS: 13.6.0
enhancement plugins

All 8 comments

@kamilkisiela can you please take a look?

@dotansimha I don't think there's something we could do... It's TypeScript that has no idea how to compare a string with an actual value.

adding as const will solve the problem on consumer-side.

@moun3iim In your example, if you set "LoginResponse" as const then it will treat it as a value not as a string.

This type of annotation is called const assertions. Here's more about the problem: https://devblogs.microsoft.com/typescript/announcing-typescript-3-4-rc/. It's available since TypeScript 3.4.

@dotansimha another solution but more "painful" to developers could be to let typescript-resolvers generate enum Typename { LoginResponse = 'LoginResponse' ... } and make all signatures expect an enum value. Then in resolvers instead of using __typename: 'LoginResponse' you use __typename: Typename.LoginResponse.

@kamilkisiela we can generate const assertions in base typescript already, it's done by @DragorWW in https://github.com/dotansimha/graphql-code-generator/pull/3569 , is it enough for that? or something is still missing?

@dotansimha I don't think there's something we could do... It's TypeScript that has no idea how to compare a string with an actual value.

adding as const will solve the problem on consumer-side.

@moun3iim In your example, if you set "LoginResponse" as const then it will treat it as a value not as a string.

This type of annotation is called const assertions. Here's more about the problem: https://devblogs.microsoft.com/typescript/announcing-typescript-3-4-rc/. It's available since TypeScript 3.4.

@dotansimha another solution but more "painful" to developers could be to let typescript-resolvers generate enum Typename { LoginResponse = 'LoginResponse' ... } and make all signatures expect an enum value. Then in resolvers instead of using __typename: 'LoginResponse' you use __typename: Typename.LoginResponse.

I can't understand, should I edit "LoginResponse" in the generated file !!

@moun3iim no, you should add it to the code you are writing :)

const signInWithEmail: MutationResolvers["signInWithEmail"] = async () => {
    return {
        __typename: "LoginResponse" as const, // < here
        token: "token"
    }
}

Looks like this is no longer working with TS 4.0.2–using "ResultName" as const does not remove the error; like OP, though, removing async does remove the error.

It makes sense, since it marks the function as real async function, and not just as a regular function that returns a Promise.
@joeyfigaro any example for the TS4.2 issue? how can I reproduce this?

Fair questions @dotansimha — I think my issue is unrelated to the issue described here. I'm going to open up a new ticket with a repro. :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iamdanthedev picture iamdanthedev  Â·  3Comments

fvisticot picture fvisticot  Â·  3Comments

leebenson picture leebenson  Â·  3Comments

dotansimha picture dotansimha  Â·  3Comments

steebchen picture steebchen  Â·  3Comments