GraphQL中MembershipType的user字段报错问题求助
问题根源与解决方案
嘿,这个错误的原因很明确——你碰到了GraphQL类型循环引用时的定义顺序问题!
为什么会报错?
看一下你的代码:你先定义了MembershipType,然后才定义UserType。当JavaScript执行到MembershipType里的user: { type: new GraphQLNonNull(UserType) }这一行时,UserType还没有被定义,此时它的值是undefined。而GraphQLNonNull要求必须传入一个有效的、可空的GraphQL类型,不能是undefined,这就触发了你看到的Expected undefined to be a GraphQL nullable type错误。
另外,我还注意到你代码里有个小笔误:UserType中memberships字段的resolve函数里,ctx的类型写成了Content,应该是Context,这个也顺手帮你修正了~
两种可行的解决方案
方案1:调整定义顺序 + 提前声明变量
我们可以先声明MembershipType变量,然后定义UserType,最后再给MembershipType赋值。这样既能解决循环引用问题,又能保证类型定义时引用的都是已存在的对象:
// 提前声明MembershipType变量,让UserType可以引用它 let MembershipType; const UserType = new GraphQLObjectType({ name: 'User', interfaces: [nodeInterface], fields: { id: globalIdField(), firstName: { type: GraphQLString, resolve(parent) { return parent.first_name; }, }, lastName: { type: GraphQLString, resolve(parent) { return parent.last_name; }, }, email: { type: GraphQLString, resolve(parent) { return parent.email; }, }, memberships: { type: new GraphQLList(MembershipType), resolve(parent, args, ctx: Context) { return ctx.membershipsByUserId.load(parent.id); }, }, membershipsCount: { type: new GraphQLNonNull(GraphQLInt), resolve(parent, args, ctx: Context) { return ctx.userMembershipsCount.load(parent.id); }, }, }, }); // 此时UserType已经完全定义,MembershipType可以安全引用它 MembershipType = new GraphQLObjectType({ name: 'Membership', interfaces: [nodeInterface], fields: { id: globalIdField(), user: { type: new GraphQLNonNull(UserType), resolve(parent, args, ctx: Context) { return ctx.userById.load(parent.user_id); }, }, role: { type: new GraphQLNonNull(GraphQLString), }, team: { type: GraphQLString, }, createdAt: { type: new GraphQLNonNull(GraphQLString), resolve(parent) { return parent.created_at; }, }, updatedAt: { type: new GraphQLNonNull(GraphQLString), resolve(parent) { return parent.updated_at; }, }, }, }); // 根据你的导出需求调整,比如分别导出 export default UserType; export { MembershipType };
方案2:用函数延迟解析字段
另一种更灵活的方式是把fields定义成函数,而不是直接的对象。函数会在所有类型都初始化完成后才执行,这样内部引用的类型都是有效的,完全不用关心定义顺序:
const MembershipType = new GraphQLObjectType({ name: 'Membership', interfaces: [nodeInterface], // 用函数返回字段对象 fields: () => ({ id: globalIdField(), user: { type: new GraphQLNonNull(UserType), resolve(parent, args, ctx: Context) { return ctx.userById.load(parent.user_id); }, }, role: { type: new GraphQLNonNull(GraphQLString), }, team: { type: GraphQLString, }, createdAt: { type: new GraphQLNonNull(GraphQLString), resolve(parent) { return parent.created_at; }, }, updatedAt: { type: new GraphQLNonNull(GraphQLString), resolve(parent) { return parent.updated_at; }, }, }), }); const UserType = new GraphQLObjectType({ name: 'User', interfaces: [nodeInterface], // 同样用函数返回字段对象 fields: () => ({ id: globalIdField(), firstName: { type: GraphQLString, resolve(parent) { return parent.first_name; }, }, lastName: { type: GraphQLString, resolve(parent) { return parent.last_name; }, }, email: { type: GraphQLString, resolve(parent) { return parent.email; }, }, memberships: { type: new GraphQLList(MembershipType), resolve(parent, args, ctx: Context) { return ctx.membershipsByUserId.load(parent.id); }, }, membershipsCount: { type: new GraphQLNonNull(GraphQLInt), resolve(parent, args, ctx: Context) { return ctx.userMembershipsCount.load(parent.id); }, }, }), }); export default UserType; export { MembershipType };
额外说明
你提到仅为Membership配置了Mutation未配置Query,这和当前的报错无关,不用纠结这一点~
内容的提问来源于stack exchange,提问作者Nizar AYARI
相关产品推荐
相关产品推荐

