Skip to content

[FEAT] Use satisfies instead of type annotation for generated resolvers #436

@koutaro-masaki

Description

@koutaro-masaki

Is your feature request related to a problem? Please describe.

When this plugin generates root object type resolvers (Query, Mutation, Subscription), it uses TypeScript type annotation style:

export const createUser: NonNullable<MutationResolvers['createUser']> = async (_parent, _arg, _ctx) => {
  /* Implement Mutation.createUser resolver logic here */
};

With type annotation, the exported variable's type is fixed to the annotated type. Because MutationResolvers['createUser'] expands to ResolverFn<...> | ResolverWithResolve<...>, the exported value carries this union type regardless of the implementation being a plain function.

As a result, importing createUser in a test file and calling it as a function is not permitted by TypeScript.

// test file
import { createUser } from './createUser';

// Error: This expression is not callable.
// Type 'ResolverWithResolve<...>' has no call signatures.
const result = await createUser(parent, args, ctx, info);

Even within the same file, where TypeScript narrows the type to ResolverFn, the 4th argument info: GraphQLResolveInfo cannot be omitted.

Describe the solution you'd like

Add an option to generate resolvers using the satisfies operator:

export const createUser = (async (_parent, _arg, _ctx) => {
  /* Implement Mutation.createUser resolver logic here */
}) satisfies NonNullable<MutationResolvers['createUser']>;

With satisfies, type checking against NonNullable<MutationResolvers['createUser']> is still enforced, but the exported variable's type is the function type inferred from the implementation. The resolver can be called directly in tests, and arguments not declared in the implementation (such as the 4th info parameter) can be omitted.

Ideally, this would apply not only to newly generated files but also to existing ones, with automatic migration of annotation-style files being configurable as well.

Describe alternatives you've considered

Manually rewriting generated files to use satisfies style works temporarily, but running codegen reverts them back to annotation style.

Additional context

satisfies was introduced in TypeScript 4.9. This plugin already requires TypeScript 5.x, so there is no additional version requirement for users.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions