#GraphQL — type safety of `@Parent`

3 messages · Page 1 of 1 (latest)

gray shuttle
#

Hi everyone! I was getting started with GraphQL code first resolvers according to the doc
https://docs.nestjs.com/graphql/resolvers

I ran into an issue with type safety. Here's an example

@Resolver(() => Author)
export class AuthorsResolver {
  @Query(() => Author)
  async author(@Args('id', { type: () => Int }) id: number) {
    return {id, firstName: 'John', lastName: 'Doe' };
  }

  @ResolveField()
  async posts(@Parent() author: Author) {
    // Well, we have the id, everything as expected
    const { id } = author;
    console.log({ id });

    // The type of `posts` is `Post[]`!
    // So should be safe to read the property of it, right?
    const { posts } = author;

    // Uh-oh... 🛑 "Cannot read properties of undefined (reading 'length')"
    console.log(posts.length);

    // return this.postsService.findAll({ authorId: id });
    return [];
  }
}

The docs suggest declaring the resolver parent as author: Author, but in reality the type is "whatever was returned from the parent resolver", not Author. Is there something I'm missing here?

forest scaffold
#

I found that it's best to only define fields from the database on Author model.
Nest will merge this declaration with all defined resolvers, so in your case, I'd do:

@ObjectType()
export class Author {
    @Field(() => Int) id!: number;
    @Field(() => String) firstName!: string;
    @Field(() => String) lastName!: string;
    // no posts field here
}

@Resolver(() => Author)
export class AuthorsResolver {
  @Query(() => Author)
  async author(@Args('id', { type: () => Int }) id: number) {
    return {id, firstName: 'John', lastName: 'Doe' };
  }

  @ResolveField(() => [Post]) // full field definition here
  async posts(@Parent() author: Author) {
    // Well, we have the id, everything as expected
    const { id } = author;
    console.log({ id });

    // posts are not on the Author type, TS won't let us
    const { posts } = author;

    // return this.postsService.findAll({ authorId: id });
    return [];
  }
}

// Resulting schema:
type Author {
    id: Int!
    firstName: String!
    lastName: String!
    posts: [Post!]!
}
gray shuttle
#

This is exactly what I was looking for! Thank you.
I wouldn't guess that a field not included in the model can still appear in the schema...