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

在GraphQL Pothos(Next.js)中实现类来源ObjectType的引用类型

解决GraphQL Pothos中类生成ObjectType的引用错误

错误原因分析

你遇到的Ref function String() { [native code] } has not been implemented错误,根源有两个:

  • 多余的无效声明:你手动写了const MoneyType = builder.objectRef<MoneyShape>("Money");,但MoneyShape从未定义,且这行完全没必要——你已经通过builder.objectType(Money)把类转换成了GraphQL类型,不需要额外创建引用。
  • 类型定义顺序问题:原代码先定义Cart类型,后定义Money类型,若解开subTotal字段注释,会出现引用未注册类型的问题。

修复方案

按以下步骤修改代码即可解决:

  1. 删除无效的objectRef代码
    直接删掉这行无意义的声明:
const MoneyType = builder.objectRef<MoneyShape>("Money");
  1. 调整类型定义顺序
    先定义被依赖的CartItem和Money类型,再定义Cart类型,确保Cart引用Money时类型已完成注册。

  2. 恢复并修正Cart的subTotal字段
    解开subTotal的注释,确保resolve函数返回合法的Money实例,适配现有数据结构。

修改后的完整服务器代码

import { createServer } from '@graphql-yoga/node'
import SchemaBuilder from "@pothos/core"
import { CartItem, Cart, Money } from 'gql';

const CARTS = [
    {
        id: '1',
        items: [
            {
                id: '1',
                name: 'Item 1',
                price: 10,
                quantity: 1
            },
            {
                id: '2',
                name: 'Item 2',
                price: 20,
                quantity: 2
            }
        ]
    },
    {
        id: '2',
        items: [
            {
                id: '3',
                name: 'Item 3',
                price: 30,
                quantity: 3
            },
            {
                id: '4',
                name: 'Item 4',
                price: 40,
                quantity: 4
            }
        ]
    }
]

const builder = new SchemaBuilder({});

// 先定义CartItem类型
builder.objectType(CartItem, {
    name: "CartItem",
    description: "A cart item",
    fields: (t) => ({
        id: t.exposeString('id', {}),
        name: t.exposeString('name', {}),
        price: t.exposeInt('price', {}),
        quantity: t.exposeInt('quantity', {}),
    }),
});

// 再定义Money类型
builder.objectType(Money, {
    name: "Money",
    description: "A money",
    fields: (t) => ({
        amount: t.exposeInt('amount', {}),
        formatted: t.field({
            type: String,
            resolve: (money) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(money.amount),
        }),
    }),
});

// 最后定义Cart类型,此时Money已注册完成
builder.objectType(Cart, {
    name: "Cart",
    description: "A cart",
    fields: (t) => ({
        id: t.exposeString('id', {}),
        items: t.field({
            type: [CartItem],
            resolve: (cart) => cart.items ?? [],
        }),
        // 恢复subTotal字段
        subTotal: t.field({
            type: Money,
            resolve: (cart) => {
                const total = cart.items?.reduce((acc, item) => acc + item.price * item.quantity, 0) ?? 0;
                return new Money(total, `$${total}`);
            }
        })
    }),
});

builder.queryType({
    fields: (t) => ({
        cart: t.field({
            type: Cart,
            nullable: true,
            args: {
                id: t.arg.id({ required: true, description: "the id of the cart" }),
            },
            resolve: (_, { id }) => {
                const cart = CARTS.find((cart) => cart.id === id);
                if (!cart) {
                    throw new Error(`Cart with id ${id} not found`)
                }
                return cart
            }
        }),
        carts: t.field({
            type: [Cart],
            resolve: () => CARTS
        }),
    }),
})

const server = createServer({
    endpoint: '/api',
    schema: builder.toSchema(),
})

export default server;

额外说明

  • Pothos会自动关联builder.objectType传入的类与对应的GraphQL类型,仅在双向引用/前置引用场景下才需要手动使用objectRef,你的场景完全不需要。
  • 保持类型定义顺序:被其他类型依赖的类型要优先定义,避免Pothos找不到注册类型的问题。

内容的提问来源于stack exchange,提问作者Wayne

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:05:22