如果要在2021年使用GraphQL Code Generator,就应该使用TypedDocumentNode
这篇文章是GraphQL Advent Calendar 2020的第8天的文章。
上一篇文章是@mtsmfm先生的GraphQL反模式-孙煩悩。
简述
TypedDocumentNode是GraphQL Code Generator用于生成TypeScript代码时的一个输出选项,于2020年7月推出。
GitHub是一个基于web的版本控制系统,也是一个共享代码的平台。
GraphQL Code Generator 公式文档是指GraphQL Code Generator的官方文档。
输出结果只是一个普通的 DocumentNode 对象(通过将查询作为参数传递给 gql 函数获得),但其特点是使用了 TypeScript 的泛型来定义类型。
在新闻稿中写道:
2016年:手动输入
2017年:生成类型
2018年:生成代码
2020年:全新的TypedDocumentNode
2016年,一开始我们是手动定义类型的,但在2017年,GraphQL Code Generator问世了,它可以自动生成QueryResult和Variables的类型。
然而,在这个阶段,我们仍然需要在调用查询时手动传递自动生成的类型定义,并不能确保实际执行的查询与类型定义完全匹配。
在2018年之后,我们开始自动生成已经传递类型定义的代码。特别是对于React,自从开始生成Hooks之后,使用体验变得更好了。
2020年推出的TypedDocumentNode被宣传为一种能够替代它们的新解决方案。
操控方法
如果引用「リリース記事」中的内容并给出React Hooks的例子,传统的Hooks生成方式会如下所示。
import { useRatesQuery } from './generated';
const result = useRatesQuery({ variables: {...} });
当使用 TypedDocumentNode 时,相当于调用了生成的 Hook。
import { useQuery } from '@apollo/client';
import { ratesQuery } from './generated';
const result = useQuery(ratesQuery, { variables: {...} });
将生成的 TypedDocumentNode 传递给 @apollo/client 的 useQuery。
当查看支持的库时,可以看到对于React,内置支持@apollo/client库;对于Vue,内置支持villus库。
在其他库中,它写着可以使用 patch-package 进行处理,但是当应用补丁时,可视性会变得不好,所以例如在使用 graphql-request 时,我写了一个简单包装函数如下。
export async function gqlFetch<TData = any, TVariables = Record<string, any>>(
operation: TypedDocumentNode<TData, TVariables>,
variables?: TVariables
) {
return client.request<TData, TVariables>(operation, variables);
}
优点
简化代码量减少
在传统的代码生成方法中,为了给类型赋值,需要单独生成包装函数和组件的代码,这并不会对执行产生影响,但会导致冗长的函数必定包含一个或多个间隔。由于类型推断得到了加强,这些都变得不再需要,结果就是生成的代码行数也会减少。
可以在各种场合使用
如果创建了React Hooks,如果只是使用生成的Hooks,那么写法非常简单。但是如果需要使用fetchMore、subscribeToMore、refetchQueries等Hooks以外的DocumentNode时,如果试图受益于类型,则只需要在那一部分进行复杂的写法。
在这些场景中,您只需使用TypedDocumentNode即可进行类型推理。
对于图书馆的规范变更具有强大的适应能力
由于TypedDocumentNode仅仅是带有类型的对象,所以生成的代码并不直接依赖于客户端库。
只要在 graphql-js 不做破坏性更改,客户端库的变动将不受影响。因此,GraphQL Code Generator 和客户端库的版本升级可以无需相互考虑。
在v16中,graphql-js似乎已经将TypedQueryDocumentNode作为标准功能进行了整合。不过在v15.4中,已经添加了TypedQueryDocumentNode,这是通过Twitter上的评论告知我的。
这个设计对于图书馆的开发者来说,是一个易于开发的结构。
缺点
自己生成 Hooks 可以使自己编写的代码更简洁。
看了示例代码后,使用 TypedDocumentNode 会比使用生成的 Hooks 自己编写代码的行数多。但是,如果使用代码补全等功能,这并不会造成很大的不利影响。
总结
我意识到我写到这里的内容几乎和之前写的博客文章重复,但我认为这是因为我从发布时就一直在使用,并且没有遇到什么问题,也没有负面的事情。
由于登场时间较短,所以关于在TypeScript中使用GraphQL的示例代码还比较少,但毫无疑问它将成为主流。(尽管可能很快就会发明出其他的写法…)
它与传统方法没有太大的区别,在设计上也是可靠的,因此如果需要重写代码,建议一开始就采用TypedDocumentNode。