Search code examples
graphqlapolloapollo-servertypegraphql

TypeGraphql Field and Arg decorators using custom type


I'm trying to build a resolver using type-graphql library and found that I can't define custom argument type. Here is my code:


type Hits = { [K: string]: string | number }

@Resolver()
export default class SearchResolver {
  @Query(() => [String], { nullable: true })
  @UseMiddleware(isAuthenticated)
  async searchAssetList(@Arg('hits') hits: Hits) {
    return [];
  }
}

I got an error:

NoExplicitTypeError: Unable to infer GraphQL type from TypeScript reflection system. You need to provide explicit type for argument named 'hits' of 'searchAssetList' of 'SearchResolver' class.

I also tried to define an input class:

type Hits = { [K: string]: string | number }

@ObjectType()
class SearchListInput {
  @Field(() => GraphQLObjectType)
  hits: Hits;
}

@Resolver()
export default class SearchResolver {
  @Query(() => [String], { nullable: true })
  async searchAssetList(@Arg('input') input: SearchListInput) {
    return []
  }
}

and got another error:

UnhandledPromiseRejectionWarning: Error: Cannot determine GraphQL input type for argument named 'input' of 'searchAssetList' of 'SearchResolver' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper input value?

Replacing @ObjectType with @InputType also doesn't help. How to define decorators like @Field, @Arg correctly?

Any help is appreciated. Thanks.


Solution

  • I think you are trying to have an Arg of an array whit numbers and strings in that case you should do

    @InputType()
    class HitsInput
    {
        @Field()
        Hits: [number | string];
    }
    
    @Resolver()
    export default class SearchResolver {
      @Query(() => [String], { nullable: true })
      async searchAssetList(@Arg('input') input: HitsInput) {
        return []
      }
    }
    

    if this is not the case and you want an object whit dynamic fields you need to define the object, let say if hits have Name and Id_Hits,

    @InputType()
    class HitsInput
    {
        @Field()
        Id_Hits: number;
    
        @Field()
        Name: string;
    }
    
    @Resolver()
    export default class SearchResolver {
      @Query(() => [String], { nullable: true })
      async searchAssetList(@Arg('input') input: HitsInput) {
        return []
      }
    }
    

    and if you want to have a dynamic args base in the user request I am not quite sure that it is possible, but it is possible to do this

    @InputType()
    class HitsInput
    {
        [key: string]: any;
    }