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

如何使用TypeScript和Apollo Client为GraphQL联合响应添加类型?

处理GraphQL联合类型的TypeScript类型推断方案

要让useQuery钩子的结果正确覆盖User和Error这两个联合片段的类型,有两种可行方案,优先推荐代码生成工具,避免手动编写类型时出错:

方法一:使用GraphQL Code Generator自动生成类型(推荐)

这个工具会根据你的GraphQL schema和查询语句,自动生成对应的TypeScript类型和类型安全的Apollo hooks,完美适配联合类型。

  1. 安装依赖
npm install --save-dev @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo
  1. 配置生成规则
    在项目根目录创建codegen.ts文件:
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'http://your-apollo-server-url/graphql', // 替换成你的Apollo Server地址,或者本地schema文件路径
  documents: ['./src/**/*.graphql', './src/**/*.tsx'], // 搜索项目中所有包含GraphQL查询的文件
  generates: {
    './src/generated/graphql.tsx': {
      plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'],
      config: {
        withHooks: true, // 生成useQuery等hooks
        withComponent: false,
        withHOC: false
      }
    }
  }
};

export default config;
  1. 添加生成命令并执行
    在package.json的scripts里添加:
"scripts": {
  "codegen": "graphql-codegen --config codegen.ts"
}

然后运行:

npm run codegen
  1. 使用生成的类型安全hooks
    生成完成后,你可以直接导入自动生成的useGetUserQuery钩子,它的返回数据会自动推断出user字段是User | Error | undefined类型:
import { useGetUserQuery } from './src/generated/graphql';

const UserComponent = () => {
  const { data, loading } = useGetUserQuery({ variables: { id: 'user-id-123' } });

  if (loading) return <Text>Loading...</Text>;

  if (data?.user) {
    // 通过__typename做类型窄化,TypeScript会自动识别对应的类型
    switch (data.user.__typename) {
      case 'User':
        return <Text>用户名:{data.user.username},邮箱:{data.user.email}</Text>;
      case 'Error':
        return <Text>错误:{data.user.message}</Text>;
    }
  }

  return <Text>无数据</Text>;
};

方法二:手动定义类型并指定给useQuery

如果不想用代码生成工具,可以手动定义对应的TypeScript类型,然后在useQuery中指定泛型:

  1. 定义联合类型
// 定义User类型
type User = {
  __typename: 'User';
  email: string;
  username: string;
};

// 定义Error类型(避免和全局Error类型冲突,改名QueryError)
type QueryError = {
  __typename: 'Error';
  message: string;
};

// 定义查询返回数据类型
type GetUserQueryData = {
  user: User | QueryError | undefined;
};
  1. 在useQuery中指定泛型
import { useQuery } from '@apollo/client';
import { gql } from '@apollo/client';

const GET_USER = gql`
  query GetUser ($id: String!) {
    user(id: $id) {
      ... on User {
        email,
        username
      }
      ... on Error {
        message
      }
    }
  }
`;

const UserComponent = () => {
  const { data, loading } = useQuery<GetUserQueryData>(GET_USER, {
    variables: { id: 'user-id-123' }
  });

  if (loading) return <Text>Loading...</Text>;

  if (data?.user) {
    switch (data.user.__typename) {
      case 'User':
        return <Text>用户名:{data.user.username},邮箱:{data.user.email}</Text>;
      case 'Error':
        return <Text>错误:{data.user.message}</Text>;
    }
  }

  return <Text>无数据</Text>;
};

注意:不管用哪种方法,都要确保你的Apollo Server的GraphQL schema中正确定义了联合类型:

type User {
  email: String!
  username: String!
}

type Error {
  message: String!
}

union UserResult = User | Error

type Query {
  user(id: String!): UserResult
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:11:04