联合类型
联合类型与接口非常相似,但它们不能指定类型之间的任何公共字段(更多信息请参阅这里)。联合类型对于从单个字段返回不相交的数据类型非常有用。
代码优先
要定义 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(() => [ResultUnion])
search(): Array<typeof ResultUnion> {
return [new Author(), new Book()];
}这将在 SDL 中生成以下 GraphQL schema 部分:
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;
},
});Schema 优先
要在 schema 优先方式中定义联合类型,只需使用 SDL 创建 GraphQL 联合类型。
type Author {
name: String!
}
type Book {
title: String!
}
union ResultUnion = Author | Book然后,你可以使用类型生成功能(如快速开始章节所示)来生成相应的 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 schema 部分:
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 schema:
"""
The supported colors.
"""
enum AllowedColor {
"""
The default color.
"""
RED
GREEN
BLUE @deprecated(reason: "Too blue.")
}Schema 优先
要在 schema 优先方式中定义枚举,只需使用 SDL 创建 GraphQL 枚举。
enum AllowedColor {
RED
GREEN
BLUE
}然后你可以使用类型生成功能(如快速开始章节所示)来生成相应的 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,
},
});