联合类型和枚举
联合类型和枚举
联合类型
联合类型与接口非常相似,但它们不指定类型之间的任何公共字段(了解更多请参阅这里)。联合类型对于返回不相关对象类型非常有用。
代码优先
要定义 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 函数注册 Result 联合:
import { createUnionType } from '@nestjs/graphql';
export const ResultUnion = createUnionType({
name: 'Result',
types: () => [Author, Book],
});
现在,在我们的解析器中注册 ResultUnion:
@Resolver()
export class AuthorResolver {
@Query(() => [ResultUnion])
search(): Array<typeof ResultUnion> {
return [new Author(), new Book()];
}
}
这将在 SDL 中生成以下 GraphQL 模式部分:
type Author {
name: String!
}
type Book {
title: String!
}
union Result = Author | Book
库生成的默认 resolveType() 函数根据解析器方法返回的值提取类型。这意味着您必须返回类实例(不能返回字面量 JavaScript 对象)。
要提供自定义的 resolveType() 函数,请将 resolveType 属性添加到传入 createUnionType() 函数的选项对象中,如下所示:
export const ResultUnion = createUnionType({
name: 'Result',
types: () => [Author, Book],
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 Result = Author | Book
然后,您可以使用类型生成功能(如快速开始章节所示)来生成相应的 TypeScript 定义:
export class Author {
name: string;
}
export class Book {
title: string;
}
export type Result = Author | Book;
联合需要在解析器映射中有一个额外的 __resolveType 字段来确定联合应该解析为哪种类型(这与接口相同)。另外,请注意,Result 联合必须在 GraphQLModule 配置中的 resolvers 映射中定义:
export const resolvers = {
Result: {
__resolveType(value) {
if (value.name) {
return 'Author';
}
if (value.title) {
return 'Book';
}
return null;
},
},
};
枚举
枚举类型是一种特殊的标量,限制为一组特定的允许值(了解更多请参阅这里)。这允许您:
- 验证此类型的任何参数都是允许值之一
- 通过类型系统传达字段将始终是有限值集合之一
代码优先
使用代码优先方法时,您可以通过创建一个 TypeScript 枚举并用 registerEnumType 函数装饰它来定义 GraphQL 枚举类型。
import { registerEnumType } from '@nestjs/graphql';
export enum AllowedColor {
RED,
GREEN,
BLUE,
}
registerEnumType(AllowedColor, {
name: 'AllowedColor',
});
registerEnumType 函数从 @nestjs/graphql 包中导出。
现在您可以在我们的类型中引用 AllowedColor 枚举:
import { Field, InputType } from '@nestjs/graphql';
import { AllowedColor } from './allowed-color.enum';
@InputType()
export class CreateCatInput {
@Field()
name: string;
@Field(() => AllowedColor)
color: AllowedColor;
}
这将在 SDL 中生成以下 GraphQL 模式部分:
enum AllowedColor {
RED
GREEN
BLUE
}
要为枚举提供描述,请将 description 属性传递给 registerEnumType() 函数。
registerEnumType(AllowedColor, {
name: 'AllowedColor',
description: '支持的猫咪颜色。',
});
要弃用枚举值或为其提供描述,请传递 valuesMap 属性:
registerEnumType(AllowedColor, {
name: 'AllowedColor',
description: '支持的猫咪颜色。',
valuesMap: {
RED: {
description: '红色。',
},
GREEN: {
description: '绿色。',
deprecationReason: '不再支持',
},
},
});
这将在 SDL 中生成以下 GraphQL 模式部分:
"""
支持的猫咪颜色。
"""
enum AllowedColor {
"""
红色。
"""
RED
"""
绿色。
"""
GREEN @deprecated(reason: "不再支持")
BLUE
}
模式优先
要在模式优先方法中定义枚举,只需使用 SDL 创建一个 GraphQL 枚举。
enum AllowedColor {
RED
GREEN
BLUE
}
然后,您可以使用类型生成功能(如快速开始章节所示)来生成相应的 TypeScript 定义:
export enum AllowedColor {
RED,
GREEN,
BLUE,
}
有时后端内部使用的值与公共 API 中的值不同。在这个例子中,API 包含 RED、GREEN 和 BLUE,而在解析器中我们可能使用 #f00、#0f0 和 #00f。要解决这个问题,请在解析器映射中声明一个解析器对象:
export const resolvers = {
AllowedColor: {
RED: '#f00',
GREEN: '#0f0',
BLUE: '#00f',
},
};