联合类型与接口非常相似,但它们无法指定类型之间的任何公共字段(阅读更多信息,请点击此处)。联合可用于从单个字段返回不相交的数据类型。
代码优先
要定义 GraphQL 联合类型,我们必须定义此联合将由哪些类组成。按照 Apollo 文档中的示例,我们将创建两个类。首先是 Book
:
import { Field, ObjectType } from '@nestjs/graphql'
@ObjectType()
export class Book {
@Field()
title: string
}
然后是 Author
:
import { Field, ObjectType } from '@nestjs/graphql'
@ObjectType()
export class Author {
@Field()
name: string
}
有了这个,使用从 @nestjs/graphql
包导出的 createUnionType
函数注册 ResultUnion
联合:
export const ResultUnion = createUnionType({
name: 'ResultUnion',
types: () => [Author, Book] as const,
})
createUnionType
函数的 types
属性返回的数组应该被赋予一个 const 断言。如果没有给出 const 断言,编译时会生成错误的声明文件,从另一个项目使用它时会发生错误。
现在,我们可以在查询中引用 ResultUnion
:
@Query(returns => [ResultUnion])
search(): Array<typeof ResultUnion> {
return [new Author(), new Book()];
}
这将导致在 SDL 中生成 GraphQL 模式的以下部分:
type Author {
name: String!
}
type Book {
title: String!
}
union ResultUnion = Author | Book
type Query {
search: [ResultUnion!]!
}
库生成的默认 resolveType()
函数将根据解析器方法返回的值提取类型。这意味着必须返回类实例而不是文字 JavaScript 对象。
要提供自定义的 resolveType()
函数,请将 resolveType
属性传递给传入 createUnionType()
函数的选项对象,如下所示:
export const ResultUnion = createUnionType({
name: 'ResultUnion',
types: () => [Author, Book] as const,
resolveType(value) {
if (value.name) {
return Author
}
if (value.title) {
return Book
}
return null
},
})
架构优先
要在模式优先方法中定义联合,只需使用 SDL 创建 GraphQL 联合即可。
type Author {
name: String!
}
type Book {
title: String!
}
union ResultUnion = Author | Book
然后,您可以使用 typings 生成功能(如 快速入门 章节中所示)来生成相应的 TypeScript 定义:
export class Author {
name: string
}
export class Book {
title: string
}
export type ResultUnion = Author | Book
联合需要解析器映射中的额外 __resolveType
字段来确定联合应解析为哪种类型。另请注意,ResultUnionResolver
类必须在任何模块中注册为提供程序。让我们创建一个 ResultUnionResolver
类并定义 __resolveType
方法。
@Resolver('ResultUnion')
export class ResultUnionResolver {
@ResolveField()
__resolveType(value) {
if (value.name) {
return 'Author'
}
if (value.title) {
return 'Book'
}
return null
}
}
所有装饰器均从 @nestjs/graphql
包中导出。
枚举
枚举类型是一种特殊的标量,仅限于一组特定的允许值(阅读更多信息 此处)。这允许您:
- 验证此类型的任何参数是否是允许值之一
- 通过类型系统传达字段始终是一组有限值之一的信息
代码优先
使用代码优先方法时,只需创建 TypeScript 枚举即可定义 GraphQL 枚举类型。
export enum AllowedColor {
RED,
GREEN,
BLUE,
}
有了这个,使用从 @nestjs/graphql
包导出的 registerEnumType
函数注册 AllowedColor
枚举:
registerEnumType(AllowedColor, {
name: 'AllowedColor',
})
现在您可以在我们的类型中引用 AllowedColor
:
@Field(type => AllowedColor)
favoriteColor: AllowedColor;
这将导致在 SDL 中生成 GraphQL 模式的以下部分:
enum AllowedColor {
RED
GREEN
BLUE
}
要为枚举提供描述,请将description
属性传递到registerEnumType()
函数中。
registerEnumType(AllowedColor, {
name: 'AllowedColor',
description: 'The supported colors.',
})
要提供枚举值的描述,或将值标记为已弃用,请传递valuesMap
属性,如下所示:
registerEnumType(AllowedColor, {
name: 'AllowedColor',
description: 'The supported colors.',
valuesMap: {
RED: {
description: 'The default color.',
},
BLUE: {
deprecationReason: 'Too blue.',
},
},
})
这将在 SDL 中生成以下 GraphQL 模式:
"""
The supported colors.
"""
enum AllowedColor {
"""
The default color.
"""
RED
GREEN
BLUE @deprecated(reason: "Too blue.")
}
模式优先
要以模式优先方法定义枚举器,只需使用 SDL 创建一个 GraphQL 枚举。
enum AllowedColor {
RED
GREEN
BLUE
}
然后,您可以使用 typings 生成功能(如 快速入门 章节中所示)来生成相应的 TypeScript 定义:
export enum AllowedColor {
RED,
GREEN,
BLUE,
}
有时,后端会在内部强制枚举使用与公共 API 不同的值。在此示例中,API 包含RED
,但在解析器中,我们可能会改用#f00
(阅读更多信息,请此处)。为此,请为AllowedColor
枚举声明一个解析器对象:
export const allowedColorResolver: Record<keyof typeof AllowedColor, any> = {
RED: '#f00',
}
所有装饰器均从@nestjs/graphql
包中导出。
然后将此解析器对象与GraphQLModule#forRoot()
方法的resolvers
属性一起使用,如下所示:
GraphQLModule.forRoot({
resolvers: {
AllowedColor: allowedColorResolver,
},
})