如何在NestJs的ObjectType类中设置联合类型属性?
问题解决:GraphQL ObjectType中定义多类型字段
核心原因
你遇到的问题本质是GraphQL本身不支持标量类型的联合(如String | [String] | Boolean),TypeGraphQL/NestJS GraphQL的@Field装饰器无法直接识别TypeScript的联合标量类型,而createUnionType仅用于对象类型的联合,不能传入TypeScript基本类型(如string是类型而非值,所以报错)。
以下是两种可行的解决方案:
方案1:使用JSON标量(最简单)
直接借助JSON标量类型,它可以兼容字符串、字符串数组、布尔值等JSON支持的类型,同时保持TypeScript类型约束。
代码示例
// TypeGraphQL 写法 import { ObjectType, Field } from 'type-graphql'; import { GraphQLJSON } from 'graphql-type-json'; // 或 NestJS GraphQL 写法 // import { ObjectType, Field } from '@nestjs/graphql'; // import { JSON } from '@nestjs/graphql'; @ObjectType() class Input { @Field() id: string; @Field() label: string; @Field() element: Element; // 假设Element是已定义的ObjectType // 用JSON标量对应TS联合类型 @Field(() => GraphQLJSON) defaultValue: string | string[] | boolean; }
方案2:自定义严格校验的标量类型
如果需要严格限制仅允许字符串、字符串数组、布尔值,可自定义标量实现类型校验:
步骤1:创建自定义标量
import { ObjectType, Field, Scalar, CustomScalar } from 'type-graphql'; import { ValueNode, Kind } from 'graphql'; @Scalar('DefaultValueScalar') export class DefaultValueScalar implements CustomScalar<string | string[] | boolean, string | string[] | boolean> { description = '仅接受字符串、字符串数组或布尔值的自定义标量'; // 解析客户端传入的值 parseValue(value: unknown): string | string[] | boolean { if (typeof value === 'string' || typeof value === 'boolean') return value; if (Array.isArray(value) && value.every(item => typeof item === 'string')) return value; throw new Error('defaultValue必须是字符串、字符串数组或布尔值'); } // 序列化服务端返回的值 serialize(value: unknown): string | string[] | boolean { return this.parseValue(value); } // 解析GraphQL AST节点 parseLiteral(ast: ValueNode): string | string[] | boolean { switch (ast.kind) { case Kind.STRING: return ast.value; case Kind.BOOLEAN: return ast.value; case Kind.LIST: const arrValues = ast.values.map(item => { if (item.kind !== Kind.STRING) throw new Error('数组元素必须是字符串'); return item.value; }); return arrValues; default: throw new Error('defaultValue必须是字符串、字符串数组或布尔值'); } } }
步骤2:在ObjectType中使用
@ObjectType() class Input { @Field() id: string; @Field() label: string; @Field() element: Element; @Field(() => DefaultValueScalar) defaultValue: string | string[] | boolean; }
注意:需要在构建Schema时注册该自定义标量(TypeGraphQL的buildSchema或NestJS的GraphQL模块中配置)。
不推荐的方案:对象类型联合
如果硬要用createUnionType,需要把每种类型包装成对象,但会让API结构复杂化,客户端需额外判断类型字段:
@ObjectType() class StringValue { @Field() type: 'string'; @Field() value: string; } @ObjectType() class StringArrayValue { @Field() type: 'stringArray'; @Field(() => [String]) value: string[]; } @ObjectType() class BooleanValue { @Field() type: 'boolean'; @Field() value: boolean; } const DefaultValueUnion = createUnionType({ name: 'DefaultValueUnion', types: () => [StringValue, StringArrayValue, BooleanValue] as const, }); @ObjectType() class Input { // ...其他字段 @Field(() => DefaultValueUnion) defaultValue: StringValue | StringArrayValue | BooleanValue; }
内容的提问来源于stack exchange,提问作者Igal
相关产品推荐
相关产品推荐

