Skip to main content

联合与枚举

联合类型

联合类型与接口非常相似,但它们不能指定类型之间的任何公共字段(阅读更多)。 联合对于从单个字段返回不同的数据类型很有用。

代码优先方式

要定义 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,
});
warning

createUnionType 函数的 types 属性返回的数组应该给出一个 const 断言。 如果不提供 const 断言,将在编译时生成错误,而在从另一个项目使用时将会出现错误。

现在,我们可以在查询中引用 ResultUnion

@Query(returns => [ResultUnion])
search(): Array<typeof ResultUnion> {
return [new Author(), new Book()];
}

这将导致生成 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

然后,您可以使用生成类型的功能(如快速入门章节所示)生成相应的 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;
}
}
tip

所有装饰器都是从 @nestjs/graphql 包导出的。

枚举

枚举类型是一种特殊类型的标量,其限制为特定一组允许的值(阅读更多)。这允许您:

  • 验证此类型的任何参数是否是允许的值之一
  • 通过类型系统传达字段将始终是有限值集之一

首选代码方式

在使用首选代码方式时,只需通过简单地创建 TypeScript 枚举来定义 GraphQL 枚举类型。

export enum AllowedColor {
RED,
GREEN,
BLUE,
}

有了这个,使用从 @nestjs/graphql 包导出的 registerEnumType 函数注册 AllowedColor 枚举:

registerEnumType(AllowedColor, {
name: 'AllowedColor',
});

现在,您可以在我们的类型中引用 AllowedColor

@Field(type => AllowedColor)
favoriteColor: AllowedColor;

这将导致生成以下部分的 GraphQL 模式:

enum AllowedColor {
RED
GREEN
BLUE
}

要为枚举提供描述,请将描述属性传递给 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.',
},
},
});

这将在 GraphQL 模式中生成以下内容:

"""
The supported colors.
"""
enum AllowedColor {
"""
The default color.
"""
RED
GREEN
BLUE @deprecated(reason: "Too blue.")
}

模式优先方式

在模式优先方式中,只需通过 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',
};
tip

所有装饰器都是从 @nestjs/graphql 包导出的。

然后,与 GraphQLModule#forRoot() 方法的 resolvers 属性一起使用此解析器对象, 如下所示:

GraphQLModule.forRoot({
resolvers: {
AllowedColor: allowedColorResolver,
},
});