TypeScript React中Apollo GraphQL数据响应属性访问优化方案咨询
React迁移TypeScript时简化Apollo useQuery类型处理的最佳实践
问题背景
正在将非TypeScript的React应用迁移至TypeScript,当前处理Apollo useQuery返回数据的方式是手动为每个查询定义响应接口,但需迁移的查询数量庞大,希望找到更高效的方案。同时,按照Apollo指引使用生成的gql函数时,出现了DocumentNode无效的编译错误。
当前手动实现流程:
- 用
graphql-tag定义查询:
import gql from 'graphql-tag'; export const FETCH_COMMENTS = gql(` query GetComments($entityId: ID!, $context: String!) { commentsByEntityIdAndContext(entityId: $entityId, context: $context) { totalCount items { id createdByName createdDate value } } } `);
- 手动声明响应接口并传入
useQuery:
import { CommentsByEntityIdAndContextCollectionSegment } from '../src/generated/gql'; interface CommentsQueryResponse { commentsByEntityIdAndContext?: CommentsByEntityIdAndContextCollectionSegment } const { loading, error, data } = useQuery<CommentsQueryResponse>(FETCH_COMMENTS, { variables: { entityId: entityId, context: context }, fetchPolicy: "cache-and-network", nextFetchPolicy: "cache-first" });
核心解决方案:利用TypedDocumentNode自动推导类型
1. 修复类型生成配置
你当前生成的gql文件中documents数组为空,说明GraphQL Code Generator未正确扫描到查询文件。调整生成工具配置(如codegen.ts),确保生成带类型的TypedDocumentNode:
// codegen.ts import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './path/to/your/schema.graphql', // 指向你的GraphQL Schema documents: './src/**/*.{ts,graphql}', // 扫描所有包含查询的TS/GraphQL文件 generates: { './src/generated/gql/': { preset: 'client', presetConfig: { gqlTagName: 'gql', // 和代码中使用的查询标签保持一致 }, config: { typedDocumentNode: true, // 关键:启用TypedDocumentNode生成 }, }, }, }; export default config;
2. 使用生成的gql函数定义查询
重新运行生成命令(如npm run generate)后,直接用生成的gql函数定义查询,它会自动返回带响应类型和变量类型的TypedDocumentNode:
import { gql } from '../src/generated/gql'; // FETCH_COMMENTS自动携带查询的完整类型信息 export const FETCH_COMMENTS = gql(` query GetComments($entityId: ID!, $context: String!) { commentsByEntityIdAndContext(entityId: $entityId, context: $context) { totalCount items { id createdByName createdDate value } } } `);
3. 无需手动指定泛型,useQuery自动推导类型
使用生成的查询时,useQuery会自动从TypedDocumentNode中解析响应类型和变量类型,无需手动声明:
import { useQuery } from '@apollo/client'; import { FETCH_COMMENTS } from './your-queries-file'; const { loading, error, data } = useQuery(FETCH_COMMENTS, { variables: { entityId: '123', context: 'post' }, // 变量类型自动校验 fetchPolicy: "cache-and-network", nextFetchPolicy: "cache-first" }); // data自动拥有正确的类型,直接访问data?.commentsByEntityIdAndContext?.items即可
4. 解决之前的编译错误
之前的错误原因是生成工具未正确生成DocumentNode实例,修复方式:
- 确保配置中的
documents路径能覆盖所有查询文件 - 启用
typedDocumentNode选项,让生成工具输出合法的DocumentNode
临时简化方案(无需调整生成配置时)
如果暂时无法修改生成工具配置,可直接使用生成的查询类型,避免手动写接口:
import { useQuery } from '@apollo/client'; import { GetCommentsQuery } from '../src/generated/gql'; // 生成工具自动为GetComments查询生成的类型 import { FETCH_COMMENTS } from './your-queries-file'; const { loading, error, data } = useQuery<GetCommentsQuery>(FETCH_COMMENTS, { variables: { entityId: entityId, context: context }, });
内容的提问来源于stack exchange,提问作者Stewart Alan
相关产品推荐
相关产品推荐

