11

Type script is showing error not mentioning argument type for each arguments:

  Mutation: {
    createUser: (parent, args, context, info) =>{

    }

I can solve by using any type, but what are the correct types?

  Mutation: {
    createUser: (parent: any, args: any, context: any, info: any) =>{

    }

enter image description here

Lin Du
  • 88,126
  • 95
  • 281
  • 483
Rafiq
  • 8,987
  • 4
  • 35
  • 35
  • 1
    Shouldn't it be `createUser: { resolve: (parent, args, context, info) => `? Specifying the types should be optional anyway. – loganfsmyth Jun 04 '21 at 00:36

1 Answers1

13

If you enable all strict type-checking options in tsconfig.json, you should add TS type for everything.

Let's take a look at the type of resolver.

export declare type IFieldResolver<TSource, TContext, TArgs = Record<string, any>> = (source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo & {
 mergeInfo: MergeInfo;
}) => any;

Resolver arguments:

parent - For resolvers of top-level fields with no parent (such as fields of Query, Mutation), this value is undefined. So the TS type is undefined

args - As you can see from the type, it must meet the type parameters in generic constraints Record<string, any>. Since the actual parameter is passed from the Graphql client, we need to define the Args type/interface for each resolver.

context - It's a generic parameter, we need to define the application context interface by ourselves.

info - The TS type already there GraphQLResolveInfo & { mergeInfo: MergeInfo }

An working example:

E.g.

import express from 'express';
import { ApolloServer, gql, MergeInfo } from 'apollo-server-express';
import { GraphQLResolveInfo } from 'graphql';

const app = express();

const typeDefs = gql`
  type User {
    email: String!
  }
  type Query {
    user: User
  }
  type Mutation {
    createUser(email: String!, password: String!): Boolean
  }
`;

export declare type IFieldResolver<TSource, TContext, TArgs = Record<string, any>> = (source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo & {
 mergeInfo: MergeInfo;
}) => any;

type CreateUserArgs = {
  email: string;
  password: string;
};

interface AppContext {
  userService: UserService;
}

const resolvers = {
  Query: {},
  Mutation: {
    createUser: (
      parent: undefined,
      args: CreateUserArgs,
      context: AppContext,
      info: GraphQLResolveInfo & { mergeInfo: MergeInfo },
    ) => {
      console.log(parent);
      return context.userService.createUser(args.email, args.password);
    },
  },
};

interface UserService {
  createUser(email: string, password: string): boolean;
}
class UserServiceImpl {
  createUser(email: string, password: string) {
    return true;
  }
}
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: {
    userService: new UserServiceImpl(),
  },
});
server.applyMiddleware({ app, path: '/graphql' });
app.listen(8080, () => console.log('Apollo server started at http://localhost:8080'));

package versions:

"typescript": "^3.9.6",
"apollo-server": "^2.15.1",
"graphql": "^14.6.0",

GraphQL Query in client-side:

mutation{
  createUser(email: "teresa@gmail.com", password: "1234")
}

Response:

{
  "data": {
    "createUser": true
  }
}

Logs in server-side:

Apollo server started at http://localhost:8080
undefined
Lin Du
  • 88,126
  • 95
  • 281
  • 483
  • 3
    Seems to me that your context type is incorrect... What about datasources etc ? Do you know if there is a built in Context type ? – Ernest Jones Sep 15 '21 at 15:27
  • @ErnestJones If you have a new question, please ask a new question. Create a minimal, reproducible code example to explain your question – Lin Du Mar 04 '22 at 02:02