如何通过@graphql-codegen/cli生成GraphQL查询的NodeType类型?
问题描述
我编写了如下GraphQL查询:
export const GET_ALL_ADVERT_CUSTOM_FIELD = gql(` query advertCustomFields { advertCustomFields { nodes { slug valueType displayName description canRead } } } `)
我希望在React组件中获取过滤后的nodes列表:
import { Props as SelectProps } from 'react-select' import React, { FC, useState } from 'react' import ObjectSelector from 'components/Common/ObjectSelector' import OptionWithDescription from './OptionWithDescription' import { useQuery } from '@apollo/client' import { AdvertCustomFieldsDocument } from '__generated__/graphql' export const AdvertCustomFieldSelector: FC<SelectProps> = (props) => { const [data, setData] = useState<NodeType[]>() useQuery(AdvertCustomFieldsDocument, { onCompleted: (res) => { const filterData = res.advertCustomFields?.nodes?.filter((e) => e.canRead) setData(filterData) }, }) return ( <ObjectSelector<Node> name={props.name} onChange={props.onChange} options={data as any} getOptionLabel={(option) => option?.displayName as string} getOptionValue={(option) => `${option.slug}`} components={{ Option: OptionWithDescription }} /> ) }
当前问题是@graphql-codegen/cli未导出NodeType类型,我的codegen配置如下:
import { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: './app/graphql/schema.graphql', documents: ['./facerberus/components/**/*.ts'], ignoreNoDocuments: true, // for better experience with the watcher generates: { './facerberus/__generated__/': { preset: 'client', plugins: [], presetConfig: { gqlTagName: 'gql', }, }, }, } export default config
请问需要调整哪些配置让codegen导出NodeType类型,或如何通过TypeScript实现该需求?
解决方案
方法一:调整Codegen配置生成显式类型
通过添加typescript和typescript-operations插件,并开启相关配置,让codegen导出更明确的子类型:
import { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: './app/graphql/schema.graphql', documents: ['./facerberus/components/**/*.ts'], ignoreNoDocuments: true, generates: { './facerberus/__generated__/': { preset: 'client', plugins: ['typescript', 'typescript-operations'], presetConfig: { gqlTagName: 'gql', // 开启导出子类型,确保节点类型被单独导出 exportFragmentSpreadSubTypes: true, // 可选:导出所有生成的类型 exportAllTypes: true }, config: { skipTypename: false, enumsAsTypes: true } }, }, } export default config
重新运行codegen后,你可以在__generated__/graphql.ts中找到对应节点的类型(比如命名为AdvertCustomFieldsAdvertCustomFieldsNodes或根据schema定义的名称),直接导入使用:
import { AdvertCustomFieldsAdvertCustomFieldsNodes as NodeType } from '__generated__/graphql'
方法二:从查询结果类型中提取节点类型
如果不想修改配置,可直接通过TypeScript的类型推导从生成的查询类型中提取节点类型:
import { AdvertCustomFieldsQuery } from '__generated__/graphql' // 提取nodes数组的元素类型 type NodeType = NonNullable<NonNullable<AdvertCustomFieldsQuery['advertCustomFields']>['nodes']>[number] export const AdvertCustomFieldSelector: FC<SelectProps> = (props) => { const [data, setData] = useState<NodeType[]>() // 其余代码保持不变 }
这种方式无需修改codegen配置,直接利用类型推导获取目标类型,避免了any类型断言。
额外提示
- 检查你的GraphQL Schema,如果
advertCustomFields返回的节点类型是AdvertCustomField,codegen会自动生成同名类型,可直接导入使用。 - 运行codegen时添加
--watch参数,修改查询或Schema后自动更新生成的类型文件。
内容的提问来源于stack exchange,提问作者Trung Modern Coding
相关产品推荐
相关产品推荐

