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

Apollo Server嵌套解析器与TypeScript对象类型不兼容问题

Apollo Server嵌套解析器的TypeScript类型兼容问题解决

问题场景

我有如下GraphQL Schema:

type Item {
  name: String!
  color: String!
  price: Float!
}

type Query {
  items: [Item]
}

通过graphql-code-generator生成了对应的TypeScript类型(见文末)。在Apollo Server中定义了解析器:

{
  Item: {
    price: () => 1.0,
  },
  Query: {
    items: () => [
      { name: 'item1', color: 'red' },
      { name: 'item2', color: 'blue' },
    ],
  },
}

实际执行查询时功能完全正常:

query {
  items {
    name
    color
    price
  }
}

但TypeScript会抛出类型错误,提示items解析器返回的对象缺少必填的price属性。错误信息如下:

Type '() => { name: string; color: string; }[]' is not assignable to type 'Resolver<Maybe<ResolverTypeWrapper<Item>[]>, {}, ApolloContext, {}> | undefined'.
  Type '() => { name: string; color: string; }[]' is not assignable to type 'ResolverFn<Maybe<ResolverTypeWrapper<Item>[]>, {}, ApolloContext, {}>'.
    Type '{ name: string; color: string; }[]' is not assignable to type 'Maybe<ResolverTypeWrapper<Item>[]> | Promise<Maybe<ResolverTypeWrapper<Item>[]>>'.
      Type '{ name: string; color: string; }[]' is not assignable to type 'ResolverTypeWrapper<Item>[]'.
        Type '{ name: string; color: string; }' is not assignable to type 'ResolverTypeWrapper<Item>'.
          Property 'price' is missing in type '{ name: string; color: string; }' but required in type 'Item'. (tsserver 2322)

我不想把Schema中的price改成可空字段——实际场景中很多非空字段需要延迟解析(比如异步获取、性能优化),Schema必须保持正确的非空定义。

报错原因

生成的TypeScript类型把Item的price标记为必填,但TypeScript无法识别Apollo的嵌套解析器机制:父解析器返回的对象可以缺少子字段,这些字段会由对应类型的解析器补充。当前生成的类型直接要求父解析器返回完整的Item对象,导致类型检查不通过。

解决方案

1. 使用graphql-code-generator的typescript-resolvers插件(推荐)

默认生成的类型只描述了GraphQL的返回类型,而typescript-resolvers插件会生成专门针对解析器的类型,它会考虑嵌套解析器的存在,允许父解析器返回缺少子字段的对象。

修改codegen配置(比如codegen.ts),添加该插件:

import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: './schema.graphql',
  generates: {
    './src/types.ts': {
      plugins: ['typescript', 'typescript-resolvers'], // 添加typescript-resolvers
      config: {
        useIndexSignature: true,
      },
    },
  },
};

export default config;

重新生成类型后,解析器的类型会自动兼容父解析器返回不完整对象的情况,无需手动修改解析器代码。

2. 手动定义兼容的父解析器返回类型

如果暂时不想修改codegen配置,可以手动创建一个允许缺少子字段的类型,替换解析器中的返回类型:

// 定义Item的部分类型,允许缺少price
type PartialItem = Omit<Item, 'price'> & { price?: never };

const resolvers = {
  Item: {
    price: () => 1.0,
  },
  Query: {
    // 断言返回类型为PartialItem数组,让TS通过检查
    items: (): PartialItem[] => [
      { name: 'item1', color: 'red' },
      { name: 'item2', color: 'blue' },
    ],
  },
};

3. 类型断言(应急方案)

如果只是临时解决,可以用类型断言强制让TS通过检查,但不推荐长期使用(会丢失类型检查的安全性):

const resolvers = {
  Item: {
    price: () => 1.0,
  },
  Query: {
    items: () => [
      { name: 'item1', color: 'red' },
      { name: 'item2', color: 'blue' },
    ] as unknown as Item[], // 强制断言为Item数组
  },
};

生成的原始TypeScript类型

export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: { input: string; output: string; }
  String: { input: string; output: string; }
  Boolean: { input: boolean; output: boolean; }
  Int: { input: number; output: number; }
  Float: { input: number; output: number; }
};

export type Item = {
  __typename?: 'Item';
  name: Scalars['String']['output'];
  color: Scalars['String']['output'];
  price: Scalars['Float']['output'];
};

export type Query = {
  __typename?: 'Query';
  items?: Maybe<Array<Maybe<Item>>>;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:04:54