给定此架构:

interface INode {
  id: ID
}

type Todo implements INode {
  id: ID
  title: String!
}

type Query {
  node(id: ID!): INode
}

给定此类:
export default class Todo {
  constructor (public id: string, public title: string) { }

  isTypeOf(value: any): Boolean {
    return value instanceof Todo;
  }
}

使用此解析器:
type NodeArgs = {
  id: string
}
export const resolver = {
  node: ({ id }: NodeArgs) => {
    return new Todo('1', 'Todo 1');
  }
}

当我调用查询时:
query {
  node(id: "1") {
    id
    ... on Todo {
      title
    }
  }
}

然后我得到下面的返回:
{
  "errors": [
    {
      "message": "Abstract type INode must resolve to an Object type at runtime for field Query.node with value { id: \"1\", title: \"Todo 1\" }, received \"undefined\". Either the INode type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "node"
      ]
    }
  ],
  "data": {
    "node": null
  }
}

如您所见,我已经实现了isTypeOf函数,但仍然收到错误消息。

我究竟做错了什么?

笔记:
  • 我正在使用Typescript,express和express-graphql;
  • 最佳答案

    isTypeOf是在您以编程方式创建架构时传递给GraphQLObjectType的构造函数的函数。 resolveType函数和联合/接口(interface)的同上。如果使用SDL并使用buildSchema创建架构,则无法将这些函数注入(inject)到已创建的架构中,就像您无法为QueryMutation以外的类型的字段提供解析器一样。

    您有两种选择。一种选择是利用默认的resolveType行为。这将检查对象上的__typename属性,并回退到对每种实现类型调用isTypeOf,直到匹配为止。这意味着,如果您使用的是类,则要做这样的事情就足够了:

    export default class Todo {
      get __typename() {
        return 'Todo'
      }
    }
    

    更好的选择是删除buildSchema并使用makeExecutableSchema中的graphql-tools。然后,您可以直接在解析器中定义resolveType和/或isTypeOf函数。例如:
    const resolvers = {
      Query: {
        node: (obj, args, context, info) => {
          return new Todo('1', 'Todo 1')
        }
      },
      INode: {
        __resolveType: (obj, context, info) => {
          if (obj instanceof Todo) return 'Todo'
        },
      }
    }
    

    您不仅可以通过这种方式轻松定义isTypeOfresolveType,还可以轻松地为任何类型的字段添加解析器,并轻松添加自定义标量。如果仅使用buildSchema,那么您将无法(轻松地)执行任何操作。

    编辑:

    如果您更喜欢使用isTypeOf而不是resolveType,则解析器将如下所示:
    const resolvers = {
      Query: {
        node: (obj, args, context, info) => {
          return new Todo('1', 'Todo 1')
        }
      },
      Todo: {
        __isTypeOf: (obj, context, info) => {
          return obj instanceof Todo
        },
      }
    }
    

    只需一个或另一个。为您使用的每种抽象类型编写一个resolveType函数,为每种可能是抽象类型的对象类型编写一个isTypeOf

    10-08 11:09