0

I have a GraphQL resolver and schema that look like this:

import { Resolvers } from "../../generated/schema";

export const resolvers: Resolvers = {
  Query: {
    getS: async (_parent: unknown, { id }: { id: string }): Promise<GenericResponse<S>> => { ... }
    }
}

and

type Query {
  getS(id: ID!): getSResponse
}

type S {
  id: ID!,
  wac: Float!,
  beginDate: String!,
  endDate: String!,
}

type getSResponse implements GenericResponse {
  status: Status!
  data: S!
}

I'm using GraphQL codegen to check types for resolver functions with the following contents:

export type Resolvers<ContextType = any> = {
  Query?: QueryResolvers<ContextType>;
}

export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
getS?: Resolver<Maybe<ResolversTypes['getSResponse']>, ParentType, ContextType, RequireFields<QueryGetSArgs, 'id'>>;
}

export type QueryGetSArgs = {
  id: Scalars['ID']['input'];
};

export type Scalars = {
  ID: { input: string | number; output: string; }
  String: { input: string; output: string; }
  Boolean: { input: boolean; output: boolean; }
  Int: { input: number; output: number; }
  Float: { input: number; output: number; }
};

However, I am getting this typescript error:

Type '(_parent: unknown, { id }: myType) => Promise<GenericResponse<S>>' is not assignable to type 'Resolver<Maybe<ResolverTypeWrapper<GetWacPercentageResponse>>, {}, any, RequireFields<QueryGetSArgs, "id">> | undefined'.
  Type '(_parent: unknown, { id }: myType) => Promise<GenericResponse<S>>' is not assignable to type 'ResolverFn<Maybe<ResolverTypeWrapper<GetSResponse>>, {}, any, RequireFields<QueryGetSArgs, "id">>'.
    Types of parameters '__1' and 'args' are incompatible.
      Type 'RequireFields<QueryGetSArgs, "id">' is not assignable to type 'myType'.
        Types of property 'id' are incompatible.
          Type 'NonNullable<string | number>' is not assignable to type 'string'.
            Type 'number' is not assignable to type 'string'.ts(2322)

How can I fix this?

Owen Murphy
  • 153
  • 1
  • 10

2 Answers2

2

Your ID can apparently be a string or number:

  ID: { input: string | number; output: string; }

But your resolver argument has it strongly typed to a string which TS correctly points out as an issue because that resolver can receive a number as per your scalar definition of ID. You need to make that work with string or number

getS: async (_parent: unknown, { id }: { id: string | number }): Promise<GenericResponse<S>> => { ... }

But to be honest, since you already assign Resolvers type to the whole resolvers object you should just be able to completely remove the inline types and it will be inferred:

getS: async (_parent, { id }) => { ... } // `id` should automatically be inferred as string | number
adsy
  • 8,531
  • 2
  • 20
  • 31
  • thank you so much for this! I unfortunately have to strongly type everything per the TS lint rules defined in our `.eslintrc` file so the first option best suits my scenario. – Owen Murphy Jun 16 '23 at 13:55
  • Those are very bad and crazy linting rules! It's often the case sadly that many of these rules available in typescript-eslint are complete nonsense. It's total madness to opt out of inference. In this instance, 0 extra type safety is offered by doing this since its already typed in Resolvers and will also lead to more obtuse errors. It will also make refactoring harder. Basically, no benefit whatsoever and a time waster. – adsy Jun 16 '23 at 14:41
1

You have

type Query {
  getS(id: ID!): getSResponse
}

Saying getS would accept id of type ID = number or string. But your resolver implementation goes like

Query: {
    getS: async (_parent: unknown, { id }: { id: string }): Promise<GenericResponse<S>> => { ... }
}

saying it would ONLY take id of type string.

Obviously there’s a contradiction here. You probably want to change your resolver param to { id: string | number }.

hackape
  • 18,643
  • 2
  • 29
  • 57