【问题标题】:Algebraic Data Types in GraphQLGraphQL 中的代数数据类型
【发布时间】:2018-05-30 03:59:59
【问题描述】:

有没有一种技术可以让我在 GraphQL 中像这样声明 ADT?

// TypeScript
type SomeAlgebraicDataType = 
  | { state: 'A', subState1: string }
  | { state: 'B', subState2: string, subState3: number }
  | { state: 'C', subState4: string, subState5: string, subState6: number }

注意如何基于state 鉴别器,推断结构的其余部分。

这里有一些伪代码来说明这个想法:

union AlgebraicDataType = StateA | StateB | StateC

type StateA {state: StateDiscriminator.A, subState1: String }
type StateB {state: StateDiscriminator.B, subState2: String, subState3: Int }
type StateC {state: StateDiscriminator.C, subState4: String, subState5: String, subState6: Int}

enum StateDiscriminator { A B C }

【问题讨论】:

    标签: graphql graphql-js algebraic-data-types


    【解决方案1】:

    根据spec

    GraphQL 联合表示一个对象,它可能是 GraphQL 对象类型列表之一,但在这些类型之间不提供保证字段。它们与接口的不同还在于 Object 类型声明了它们实现的接口,但不知道联合包含它们。

    联合(和接口)在规范中被称为 抽象 类型,因为返回联合的字段的具体(即实际)类型直到运行时才知道。但是,联合也符合 algebraic type 的一般定义,因为它们实际上是两个或多个对象类型的总和。

    问题中的伪代码离工作示例不远:

    union AlgebraicDataType = StateA | StateB | StateC
    
    type StateA {state: StateDiscriminator, subState1: String }
    type StateB {state: StateDiscriminator, subState2: String, subState3: Int }
    type StateC {state: StateDiscriminator, subState4: String, subState5: String, subState6: Int}
    
    enum StateDiscriminator { A B C }
    

    主要区别在于,当我们使用 SDL 定义模式时,我们必须指定如何将 Union 与类型定义分开解析。如果您使用来自graphql-toolsapollo-servermakeExecutableSchema,我们会将此逻辑指定为解析器映射的一部分:

    const resolvers = {
      AlgebraicDataType: {
        __resolveType: (obj) => {
          switch (obj.state) {
            case 'A': return 'StateA'
            case 'B': return 'StateB'
            case 'C': return 'StateC'
            default: {
              throw new TypeError(
                `Unknown state for AlgebraicDataType: ${obj.state}`
              )
            }
          }
        }
      }
    }
    

    如果您使用的是原版 GraphQL.js,则向 Union 的构造函数提供与 resolveType 参数相同的函数。

    另外值得注意的是,如果没有提供 resolveType 函数,默认情况下 GraphQL 将在提供的对象上查找名为 __typename 的属性并使用它来解析类型。因此,只要您在解析器中返回具有该属性的对象,就可以完全省略该函数。

    【讨论】:

      猜你喜欢
      • 2018-09-18
      • 2020-07-05
      • 1970-01-01
      • 2016-08-13
      • 2016-02-28
      • 2017-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多