You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:15:27