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

(1.3.0) Generated resolver type is not callable (and related issues) #5370

Closed
pvenable opened this issue May 1, 2022 · 3 comments · Fixed by #5437
Closed

(1.3.0) Generated resolver type is not callable (and related issues) #5370

pvenable opened this issue May 1, 2022 · 3 comments · Fixed by #5437
Assignees
Labels
bug/confirmed We have confirmed this is a bug topic/typescript

Comments

@pvenable
Copy link
Contributor

pvenable commented May 1, 2022

Note that this pertains to 1.3.0-rc.0.

#5216 improved the GraphQL codegen resolver types (and is a good change!), but it seems to create some problems with calling resolver functions from tests in TypeScript (including in generated service tests).

To reproduce a simple case:

yarn create redwood-app redwood-resolvers-not-callable --typescript
cd redwood-resolvers-not-callable
yarn rw upgrade --tag rc
yarn rw g sdl UserExample
yarn rw type-check

Several errors will appear, such as:

src/services/userExamples/userExamples.test.ts:18:26 - error TS2349: This expression is not callable.
  Not all constituents of type 'Resolver<ResolverTypeWrapper<UserExample>[], {}, RedwoodGraphQLContext, {}>' are callable.
    Type 'ResolverWithResolve<ResolverTypeWrapper<UserExample>[], {}, RedwoodGraphQLContext, {}>' has no call signatures.

18     const result = await userExamples()
                            ~~~~~~~~~~~~

A direct solution to this error could be to include makeResolverTypeCallable: true (part of https://www.graphql-code-generator.com/plugins/typescript-resolvers) in the default graphql-code-generator config.

With that said, the above change will reveal further type errors, as the resolver typings require 2 arguments, e.g.:

src/services/userExamples/userExamples.test.ts:18:26 - error TS2554: Expected 2 arguments, but got 0.

18     const result = await userExamples()
                            ~~~~~~~~~~~~~~

  types/graphql.d.ts:10:7
    10       args: TArgs,
             ~~~~~~~~~~~
    An argument for 'args' was not provided.

src/services/userExamples/userExamples.test.ts:26:28 - error TS2554: Expected 2 arguments, but got 1.

26       const result = await userExample({ id: scenario.userExample.one.id })
                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  types/graphql.d.ts:11:7
    11       obj: { root: TParent; context: TContext; info: GraphQLResolveInfo }
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    An argument for 'obj' was not provided.

It would be good to both improve the generated tests so they type-check and to demonstrate proper arguments for the new typings. It’s simple enough to add {} for args where necessary, but I think it’s non-obvious what should be passed as the second (obj) argument.

Possible solutions here might involve some sort of test helper(s) to either

  • wrap calls to the resolvers with more lenient arguments, or
  • help build valid arguments for the second (obj) parameter

Addendum: strict null checks

I will note that with strictNullChecks disabled, one can simply pass null or undefined as the second argument (or for any of root, context, or info). However, with strict: true (or even just strictNullChecks: true) in tsconfig.json, things get a bit more complicated with errors like:

Type of 'await' operand must either be a valid promise or must not contain a callable 'then' member. ts(1320)

and

Cannot invoke an object which is possibly 'undefined'. ts(2722)

I haven't quite figured out why the 'await' operand error occurs, but I have been able to work around it by overriding customResolverFn to return Promise<TResult> | TResult instead of Promise<Partial<TResult>> | Partial<TResult> -- though there may be drawbacks to this, so I'm not necessarily proposing it as a solution.

For the second error I've been using a helper that accepts a Partial of the second (obj) argument and basically

  • throws on an undefined resolver function
  • otherwise proceeds to call the function by casting the Partial obj argument to the correct non-Partial type (basically a hack).
@pvenable
Copy link
Contributor Author

pvenable commented May 3, 2022

As 1.3.0 has now been released, this issue applies to 1.3.0 as well.

Updated repro without needing to upgrade to rc:

yarn create redwood-app redwood-resolvers-not-callable --typescript
cd redwood-resolvers-not-callable
yarn rw g sdl UserExample
yarn rw type-check

@dac09
Copy link
Collaborator

dac09 commented May 4, 2022

Thank you for the detailed bug report and the reproduction @pvenable - much appreciated!

I will look at this ASAP!

(cc @orta just FYI)

@dac09 dac09 changed the title (1.3.0-rc.0) Generated resolver type is not callable (and related issues) (1.3.0) Generated resolver type is not callable (and related issues) May 4, 2022
@dac09 dac09 added bug/confirmed We have confirmed this is a bug topic/typescript labels May 4, 2022
@orta
Copy link
Contributor

orta commented May 4, 2022

Cool, this all makes sense - makeResolverTypeCallable seems like a solid win.

I wonder if Redwood should provide a function for in testing that's like a resolverContextFake which can be arbitrarily passed in during tests (inside prod code you'd be fine to pass along your current context)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/confirmed We have confirmed this is a bug topic/typescript
Projects
Status: Archived
Development

Successfully merging a pull request may close this issue.

5 participants