GraphQL联合类型resolveType替代方案及报错排查求助
问题描述
我希望通过单个GraphQL查询返回byte字段的不同数据类型(字符串或数组),但遇到报错:
'Abstract type "GetRecordsWrapper" must resolve to an Object type at runtime for field "Query.records". Either the "GetRecordsWrapper" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.'
我已在Resolver类中添加__resolveType函数,但错误仍存在。相关代码如下:
Records Resolver
import { Resolver, Query, Mutation, Args, Subscription } from '@nestjs/graphql'; import { RecordsService } from './records.service'; import { PubSub } from 'graphql-subscriptions'; import { CreateRecordInput, UpdateRecordInput} from '../graphql'; const pubSub = new PubSub(); @Resolver('Record') export class RecordsResolver { constructor(private readonly recordsService: RecordsService) {} __resolveType(obj: any) { if (typeof obj.byte === 'string') { return 'HexByteStringResponse'; } if (Array.isArray(obj.byte)) { return 'ByteArrayResponse'; } return null; } @Query('records') async records(@Args('format') args: "byte" | "array"): Promise<any> { return this.recordsService.findAll(args); } }
Records Service
import { Injectable } from '@nestjs/common'; import { Record } from '@prisma/client'; import { PrismaService } from '../prisma/prisma.service'; import { CreateRecordInput, UpdateRecordInput, GetRecordsWrapper, HexByteStringResponse, ByteArrayResponse } from 'src/graphql'; @Injectable() export class RecordsService { constructor(private prisma: PrismaService) {} async findAll(format: "byte" | "array"): Promise<GetRecordsWrapper[]> { const records = await this.prisma.record.findMany({ include: { provider: true, }, }); return records.map(record => { if (format === "byte") { return { ...record, byte: `0x${record.byte.toString('hex')}`, } as HexByteStringResponse; } else { return { ...record, byte: Array.from(record.byte), } as ByteArrayResponse; } }); } }
GraphQL Schema
scalar DateTime scalar Bytes scalar Provider type Record { id: ID! byte: Bytes! sendedAt: DateTime! createdAt: DateTime! provider: Provider! } type HexByteStringResponse { id: ID! byte: String! sendedAt: DateTime! createdAt: DateTime! provider: Provider! } type ByteArrayResponse { id: ID! byte: [Int!]! sendedAt: DateTime! createdAt: DateTime! provider: Provider! } union GetRecordsWrapper = HexByteStringResponse | ByteArrayResponse type Query { records(format: String!): [GetRecordsWrapper]! record(id: String!): GetRecordsWrapper recordsWrapper(type: String!): GetRecordsWrapper }
请问是否有GraphQL联合类型resolveType的替代方案,或如何解决该报错?
解决方案
修复当前resolveType不生效的问题
你当前的__resolveType函数绑定到了Record类型的Resolver上,但它实际属于联合类型GetRecordsWrapper,需要为该联合类型单独创建Resolver:
- 创建联合类型专属Resolver:
import { Resolver } from '@nestjs/graphql'; @Resolver('GetRecordsWrapper') export class GetRecordsWrapperResolver { __resolveType(obj: any) { if (typeof obj.byte === 'string') { return 'HexByteStringResponse'; } if (Array.isArray(obj.byte)) { return 'ByteArrayResponse'; } return null; } }
将这个新Resolver添加到对应模块的
providers数组中,确保NestJS能加载到它。原
RecordsResolver仅保留查询逻辑即可,删除其中的__resolveType函数。
替代方案:使用isTypeOf函数
如果不想维护联合类型的resolveType,可以给每个具体类型添加isTypeOf函数来识别类型:
- 为
HexByteStringResponse创建Resolver:
import { Resolver } from '@nestjs/graphql'; @Resolver('HexByteStringResponse') export class HexByteStringResponseResolver { isTypeOf(obj: any) { return typeof obj.byte === 'string'; } }
- 为
ByteArrayResponse创建Resolver:
import { Resolver } from '@nestjs/graphql'; @Resolver('ByteArrayResponse') export class ByteArrayResponseResolver { isTypeOf(obj: any) { return Array.isArray(obj.byte); } }
- 将这两个Resolver添加到模块的
providers中,即可替代联合类型的resolveType逻辑。
额外检查点
- 确保
RecordsService返回的每个对象的byte字段类型严格匹配:格式为byte时返回字符串,array时返回数组,避免混合类型导致解析失败。 - 确认GraphQL Schema中联合类型
GetRecordsWrapper的定义正确,包含所有可能的子类型。
内容的提问来源于stack exchange,提问作者HighHill
相关产品推荐
相关产品推荐

