Interfaces

Defining Interface Types

Defining interfaces works exactly like defining Objects, using Interfaces key in TypeInfo object for the builder, and interfaceRef rather than objectRef.

Lets update our Giraffe class a bit to make it work well for interfaces:

export class Animal {
diet: Diet;
constructor(diet: Diet) {
this.diet = diet;
}
}
export class Giraffe extends Animal {
name: string;
birthday: Date;
heightInMeters: number;
constructor(name: string, birthday: Date, heightInMeters: number) {
super(Diet.HERBIVOROUS);
this.name = name;
this.birthday = birthday;
this.heightInMeters = heightInMeters;
}
}
export enum Diet {
HERBIVOROUS,
CARNIVOROUS,
OMNIVORIOUS,
}

Again, using classes is completely optional. The only requirement for interfaces is that the the type used for defining objects must be a superset of the the types of any interfaces they implement.

Now that we have our classes set up we can define the interface type. and add a enum definitions for our diet field:

builder.interfaceType(Animal, {
name: 'AnimalFromClass',
fields: (t) => ({
diet: t.expose('diet', {
type: Diet,
}),
}),
});
builder.enumType(Diet, {
name: 'Diet',
});

implementing interfaces with object types

builder.objectType(Giraffe, {
name: 'Giraffe',
interfaces: [Animal],
isTypeOf: (value) => value instanceof Giraffe,
fields: (t) => ({
name: t.exposeString('name', {}),
}),
});

There are 2 new properties here: interfaces and isTypeOf.

Interfaces is an array of interfaces that the object type implements, and isTypeOf is a function that is run whenever we have an object of the interface type and we want to see if it's actually an instance of our object type.

Using an Interface as a return type

Using interfaces as return types for fields works just like objects:

builder.queryFields((t) => ({
animal: t.field({
type: 'Animal',
resolve: () => new Giraffe('James', new Date(2012, 11, 12), 5.2),
}),
}));

Querying interface fields

We can query interface fields like diet on any field that returns a giraffe:

query {
giraffe {
name
diet
}
}

or we can query a field that returns an interface and select different fields depending on the concrete type:

query {
animal {
diet
... on Giraffe {
name
}
}
}