是否有一种技术可以让我在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 }
答案 0 :(得分:1)
根据spec:
规范中将GraphQL并集表示一个对象,该对象可以是GraphQL对象类型的列表之一,但在这些类型之间不提供任何保证的字段。它们与接口的不同之处还在于,对象类型声明它们实现的接口,但不知道包含它们的联合。
Union(和接口)称为抽象类型,因为返回Union的字段的具体(即实际)类型直到运行时才知道。但是,并集也符合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定义架构时,我们必须指定如何与类型定义分开解析联合。如果您使用的是apollo-server
中的makeExecutableSchema
或graphql-tools
,我们会将此逻辑指定为解析器映射的一部分:
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,则将相同的函数作为resolveType
参数提供给Union的构造函数。
还值得注意的是,如果未提供resolveType
函数,默认情况下GraphQL将在提供的对象上查找名为__typename
的属性,并使用该属性来解析类型。因此,只要您在解析器中返回具有该属性的对象,就可以完全省略该函数。