Skip to main content

Fields

You can define GraphQL fields by placing a @gqlField directly before a:

  • Method declaration
  • Method signature
  • Property declaration
  • Property signature
  • Parameter property
  • Function declaration
  • Static method

Class-based fields

When using classes or interfaces to define GraphQL types, fields can be defined using class properties or methods:

/** @gqlType */
class User {
/**
* A description of some field.
* @gqlField
*/
someField: string;

/** @gqlField */
myField(): string {
return "Hello World";
}
}
Playground

Fields can also be defined using TypeScript's parameter properties, wich is a short-hand for defining a field value that is passed to the class constructor:

/** @gqlType */
class User {
constructor(
/** @gqlField */
public name: string,
) {}
}
Playground

If you want to group root fields Query Mutation that return or modify a specific type, you can define them as part of that type's class using static methods:

/** @gqlType */
type Query = unknown;

/** @gqlType */
export class User {
constructor(
/** @gqlField */
public name: string,
) {}

/** @gqlField */
static getUser(_: Query): User {
return new User("Elizabeth");
}
}
Playground

Grats will use the type of the first argument of the static method to determine which type is being extended. Even if you don't need access to any values on the parent object, you must type your first argument using the parent type so that Grats knows which type your field is on.

For more information about field resolves, see Resolver Signature.

Functional style fields

If you prefer to avoid classes, types can be defined using type literals. However, this approach does not allow you to define derived/resolver fields. To solve this, Grats also allows you to define derived fields using named, exported functions. Function resolvers:

  • Accept an instance of the parent type as the first argument
  • Have a return type that matches the field type
  • Are exported named functions where the function name is the desired field name
/** @gqlType */
const User = {
/** @gqlField */
firstName: string,
/** @gqlField */
lastName: string,
};

export function fullName(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
tip

In addition to adding derived fields to type literals, functional fields are also useful to define root fields on Query or Mutation next to the type they return or modify.

Even if you don't need access to any values on the parent object, you must type your first argument using the parent type so that Grats knows which type your field is on. So you might have a field that looks like this:

/** @gqlType */
type Query = unknown;

export function hello(_: Query): string {
return "Hello World!";
}

Extending Query:

const DB: any = {};

/** @gqlType */
type Query = unknown;

/** @gqlType */
type User = {
/** @gqlField */
name: string;
};

/** @gqlField */
export function userById(_: Query, args: { id: string }): User {
return DB.getUserById(args.id);
}
Playground

Extending Mutation:

const DB: any = {};

/** @gqlType */
type Mutation = unknown;

/** @gqlType */
type User = {
/** @gqlField */
name: string;
};

/** @gqlField */
export function deleteUser(_: Mutation, args: { id: string }): boolean {
return DB.deleteUser(args.id);
}
Playground

Note that Grats will use the type of the first argument to determine which type is being extended. So, as seen in the previous examples, even if you don't need access to the instance you should still define a typed first argument.

More field documentation

  • Renaming for how to expose your field under a different name than your function/property/method
  • Field Arguments for how to define arguments
  • Descriptions for how to add descriptions to your fields
  • Nullability for how to control the error handling and nullability of your field
  • Deprecated for how to control the nullability of your field