typed-graphqlify 核心概念:如何用"单一数据源"彻底消灭重复代码?
【免费下载链接】typed-graphqlifyBuild Typed GraphQL Queries in TypeScript without the code generation项目地址: https://gitcode.com/gh_mirrors/ty/typed-graphqlify
在 TypeScript 项目里写 GraphQL 查询,最让人头疼的就是"同一份数据要写两遍":GraphQL 查询字符串一份、TypeScript 返回接口又是一份。typed-graphqlify正是为解决这个痛点而生的开源库,它用「单一数据源」的思路,让你只定义一次,就能同时得到查询与完整类型,彻底消灭重复代码。这篇面向新手的文章,将用最通俗的方式拆解它的核心概念和上手方法。
传统写法的痛点:一份数据,两处维护 😫
先用一段最常见的代码感受一下传统方式(比如配合 Apollo 使用):
interface GetUserQueryData { getUser: { id: number name: string bankAccount: { id: number; branch?: string } } } const query = graphql(gql` query getUser { user { id name bankAccount { id branch } } } `)看似没问题,但隐患不少:
| 痛点 | 具体表现 |
|---|---|
| 重复定义 | 同一个字段在接口和查询里各写一遍 |
| 容易不同步 | 新增字段忘记改接口,类型检查不会报错 |
| 维护成本高 | 字段越多,出错概率越大 |
字段一旦多起来,这种"影子接口"就成了项目里的定时炸弹。💣
核心概念:什么是"单一数据源"?
typed-graphqlify 的核心思想很简单:只写一份 GraphQL 风格的对象,查询字符串和 TypeScript 类型都从它推导出来。它通过query、mutation、subscription三个入口,配合types辅助器,把"查询定义"与"类型定义"合二为一。
看一个最基础的例子:
import { query, types } from 'typed-graphqlify' const getUserQuery = query('getUser', { user: { id: types.number, name: types.string, bankAccount: { id: types.number, branch: types.optional.string, }, }, })这一段代码同时产出了两样东西:
getUserQuery.toString():生成标准 GraphQL 查询字符串typeof getUserQuery.data:推导出完整的返回数据类型
上图展示了它在编辑器里的实际效果:输入result.user.后,id、name、bankAccount等字段立刻自动补全;branch因为是可选字段,类型被正确推断为string | undefined,把类型安全做到了指尖上。
四个核心关键词,一次搞懂
types辅助器:types.number、types.string、types.boolean声明标量类型;types.optional.xxx声明可选字段;types.oneOf处理枚举;types.constant处理常量。toString()方法:把对象渲染成 GraphQL 查询字符串,交给任意请求库执行。data属性:typeof query.data就是返回数据的类型,直接给请求结果"贴标签",无需手写接口。- 辅助函数:
params(传参数)、alias(字段别名)、fragment(复用片段)、on(内联片段)等,覆盖了日常开发九成以上的写法。
想深入源码的话,核心实现集中在
src/graphqlify.ts(操作入口与辅助函数)、src/types.ts(types 类型系统)、src/render.ts(查询渲染引擎)三个文件,代码量很小,非常适合阅读。
快速上手:一分钟跑通第一个查询
安装非常轻量:
npm install --save typed-graphqlify或者使用 Yarn:
yarn add typed-graphqlify然后写一个查询,执行并拿到类型安全的结果:
const data: typeof getUserQuery.data = await executeGraphql(getUserQuery.toString()) // data 的类型自动推导为: // { user: { id: number; name: string; bankAccount: { id: number; branch?: string } } }最妙的是,data的类型完全由查询对象推导,字段永远与查询保持一致——这就是"单一数据源"带来的最大价值。
三个高频场景速查
场景一:可选字段怎么写?
GraphQL 的可选字段用types.optional或optional()表达,返回类型自动变为xxx | undefined,可空性一目了然。
场景二:嵌套查询怎么定义?
父子层级直接嵌套对象即可,结构与查询天然对应,还能自动获得嵌套的类型推断,层级再深也不怕。
场景三:Fragment 复用方法
把公共字段抽成 Fragment,一处定义、处处复用:
const userFields = fragment('userFields', 'User', { id: types.number, name: types.string, })然后在任意查询里用...userFields展开,以后改字段只动一处,其余查询自动同步。💡
为什么不用 Apollo codegen?
你可能听说过apollo client:codegen这类"GraphQL 转 TypeScript"的代码生成工具。typed-graphqlify 与它们的关键区别在于:
| 对比项 | Apollo codegen | typed-graphqlify |
|---|---|---|
| 是否需要 schema | 通常需要下载并解析 schema | 完全不需要 |
| 构建方式 | 离线生成静态接口文件 | 运行时由对象直接推导 |
| 工具复杂度 | 工具链较重,出问题难排查 | 逻辑极简,易读易修 |
| 动态查询 | 较难支持 | 天然支持程序化构建 |
简单说:codegen 是"离线生成",typed-graphqlify 是"即写即得",尤其适合拿不到完整 schema、或需要动态拼接查询的场景。
常见问题 FAQ
Q:typed-graphqlify 支持 Mutation 和 Subscription 吗?支持。分别使用mutation和subscription入口即可,用法与query完全一致。
Q:必须搭配 Apollo 使用吗?不必须。它只负责生成查询字符串和推导类型,配合任何 GraphQL 请求库都能工作。
Q:React Native 里能用吗?可以。若目标环境是 ES5,需要为Symbol和Map引入 polyfill(例如babel-polyfill)。
小结
"单一数据源"听起来抽象,落到 typed-graphqlify 上就一句话:查询怎么写,类型就是什么,永远不用写第二遍。对新手而言,它上手成本极低;对团队而言,它把"接口与查询不同步"这类最常见的 bug 消灭在了编译期。如果你正被 TypeScript + GraphQL 的重复劳动折磨,不妨立刻装一个试试,你会回来感谢它的。🚀
【免费下载链接】typed-graphqlifyBuild Typed GraphQL Queries in TypeScript without the code generation项目地址: https://gitcode.com/gh_mirrors/ty/typed-graphqlify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考