GraphQL Codegen生成的graphql函数为何类型为unknown?
问题背景
你在React(TypeScript+Apollo)项目中使用GraphQL Codegen,配置如下:
const config: CodegenConfig = { overwrite: true, schema: path.join(__dirname, "./schema.graphql"), documents: ["src/**/*.tsx", "src/**/*.ts"], // 所有查询都在"src/queries/*.ts"下 generates: { "src/queries/__generated__/": { preset: "client", plugins: ["typescript"], }, "./graphql.schema.json": { plugins: ["introspection"], }, }, };
生成的graphql函数出现了返回unknown的兜底重载:
/** * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; {...14 other graphql function overloads }
导致Apollo的useQuery钩子报类型错误:
Argument of type 'unknown' is not assignable to parameter of type 'DocumentNode | TypedDocumentNode<any, {...queryVariables }>.'
你的查询写法示例:
import { graphql } from "./__generated__"; export const GET_DATA = graphql(` query getData($Criteria: CriteriaInputType) { dataSet(criteria: $Criteria) { pagedResult { ...FragmentTypeA ...FragmentTypeB } }, validations { key value } } ...FragmentTypeA, ...FragmentTypeB `);
错误原因及解决方案
1. Documents配置范围不当
你的documents配置匹配了所有src下的ts/tsx文件,且未排除生成的__generated__目录,这会导致Codegen读取到自身生成的文件,触发循环解析,生成兜底的unknown重载。
修改配置,精准匹配查询文件并排除生成目录:
documents: [ "src/queries/*.ts", // 仅读取查询目录下的文件 "src/**/*.tsx", // 保留组件中的查询(如果有) "!src/queries/__generated__/**/*" // 排除生成的文件,避免循环解析 ],
2. 查询语法存在错误
你的查询末尾的片段引用有多余的逗号,这会导致GraphQL语法解析失败,Codegen无法正确识别查询结构:
// 错误写法 ...FragmentTypeA, ...FragmentTypeB
修正为:
// 正确写法 ...FragmentTypeA ...FragmentTypeB
3. Codegen插件配置冗余
使用preset: "client"时,无需单独指定plugins: ["typescript"],client preset已经内置了typescript、typescript-operations等必要插件,冗余配置可能导致生成逻辑异常。
调整generates配置:
generates: { "src/queries/__generated__/": { preset: "client", // 移除单独的plugins配置,由preset自动加载所需插件 }, "./graphql.schema.json": { plugins: ["introspection"], }, },
完成以上修改后,重新运行GraphQL Codegen,返回unknown的兜底重载会消失,所有查询都会生成正确的TypedDocumentNode类型,Apollo useQuery的类型错误也会解决。
内容的提问来源于stack exchange,提问作者user1020069

