示例说明
手写 GraphQL 查询的字符串与结果类型之间没有任何联系,拼错字段名要等运行时才知道。codegen 的 typedDocumentNode 模式把查询模板转换成带完整类型的对象:变量类型来自 schema 的参数定义,结果类型来自选择集精确推导——选了 rank 与 player.name,data 的形状就只有这些字段,加删字段立即引发类型错误。
技术要点
- graphql 标签函数返回类型化文档节点
- 变量与结果类型都由 schema 推断
- 字段变更通过编译错误及时传导
代码解读
LeaderboardQuery 通过生成的 graphql 标签函数构造;组件把 region 受限为两个字面量之一,variables 的合法性由变量类型约束。useQuery 消费类型化节点后 data 自动窄化,leaderboard 数组的元素类型精确到选择集。fetchPolicy 固定缓存优先策略。
使用建议
生成文件提交或按需生成二选一并保持一致。schema 变更后立即重新生成,让破坏性改动在编译期拦截。选择集克制,只取渲染必需字段。
代码示例
import { useQuery } from '@apollo/client';
import { graphql } from '../generated/gql';
// 代码生成物由 graphql-codegen 从 schema 产出:
// const LeaderboardQuery = graphql(`
// query Leaderboard($region: Region!) {
// leaderboard(region: $region) {
// rank
// player { name }
// score
// }
// }
// `);
const LeaderboardQuery = graphql(`
query Leaderboard($region: Region!) {
leaderboard(region: $region) {
rank
player { name }
score
}
}
`);
function Leaderboard({ region }: { region: 'eu' | 'na' }) {
const { data, loading, error } = useQuery(LeaderboardQuery, {
variables: { region },
fetchPolicy: 'cache-first',
});
if (loading) return <p>loading…</p>;
if (error) return <p role="alert">failed to load leaderboard</p>;
return (
<ol>
{data?.leaderboard.map((row) => (
<li key={row.rank}>
{row.player.name} — {row.score}
</li>
))}
</ol>
);
}