When defining GraphQL types, it’s common to run into situations when two types reference each other. This is a problem because one type will be undeclared or undefined when the other is evaluated.
// Bad, `Item` is not defined (JavaScript actually means *undeclared* here)
const User = new GraphQLObjectType({
name: "User",
fields: {
id: { type: GraphQLString },
email: { type: GraphQLString },
items: {
type: new GraphQLList(Item),
resolve: () => {
/* resolve function to get user's items */
},
},
},
});
const Item = new GraphQLObjectType({
name: "Item",
fields: {
id: { type: GraphQLString },
name: { type: GraphQLString },
user: {
type: User,
resolve: () => {
/* resolve function to get user of item */
},
},
},
});
// doesn't work either - `Item` is undefined, but `type` expects a GraphQL type
let Item // declared, but has value of undefined
const User = new GraphQLObjectType({
name: 'User',
fields: {
id : { type: GraphQLString },
email: { type: GraphQLString },
items: {
type: new GraphQLList(Item),
resolve: () => { /* resolve function to get user's items */ }
},
}
})
Item = ...
To fix this, the reference JavaScript implementation allows us to indicate the fields using a function that returns an object, instead of a plain object. This function is lazily evaluated during runtime, so we will not run into problems with the interpreter.
// Works!
const User = new GraphQLObjectType({
name: "User",
fields: () => ({
id: { type: GraphQLString },
email: { type: GraphQLString },
items: {
type: new GraphQLList(Item),
resolve: () => {
/* resolve function to get user's items */
},
},
}),
});
const Item = new GraphQLObjectType({
name: "Item",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
user: {
type: User,
resolve: () => {
/* resolve function to get user of item */
},
},
}),
});