最近,很多使用 GraphQL 的前端开发者都遇到了一个问题:使用 Apollo Client 发送请求时,返回数据类型与定义的类型(比如 TypeScript 的类型或者 JavaScript 类型)不匹配。这个问题会导致编译时错误,也可能导致运行时错误,特别是在处理复杂的数据类型时,更容易发生这种情况。在本文中,我们将讨论这个问题,并提供一些解决方案。
问题的根源
GraphQL 是一种类型系统,它定义了查询语言和类型规范。使用 GraphQL 和 Apollo Client,我们可以定义查询和类型规范,然后发送请求到后端,获取返回的数据并进行处理。在处理返回的数据时,我们可能需要将它们映射到前端的类型规范中。
问题在于,GraphQL 返回的数据是 JSON 格式的,而 JavaScript 的数据类型是动态的,这就可能导致类型不匹配的问题。比如,我们定义了一个 TypeScript 接口:
interface User { name: string; age: number; }
然后,我们定义了一个查询,可以获取后端返回的用户信息:
query GetUser { user { name age } }
如果我们使用 Apollo Client 发送这个查询并在 TypeScript 中处理返回的数据,可能会遇到类型不匹配的问题。因为返回的数据结构是这样的:
{ "user": { "name": "Alice", "age": "18" } }
注意,"age" 的值是一个字符串而不是一个数字。这会导致 TypeScript 报错,因为我们定义的 User 接口中,age 的类型是 number,而返回的数据中是 string 类型。
解决方案
有几种解决方案可以解决这个问题。
1. 手动映射数据
第一种解决方案是手动映射返回的数据。我们可以使用 Apollo Client 提供的 useQuery
钩子来获取数据,并在钩子中对返回的数据进行处理和映射。比如,我们可以这样定义 useUser
:
-- -------------------- ---- ------- ------ - --------- --- - ---- ----------------- --------- ---- - ----- ------- ---- ------- - ------ -------- --------- - ----- - -------- ------ ---- - - ------------- ----- ------- - ---- - ---- --- - - --- -- ------- - ----- ------ - -- -------- -- ------ - ------ ----- - ----- - ---- - - ----- ------ - ----- ---------- ---- ----------------- -- -
在这个钩子中,我们首先使用 useQuery
获取数据。然后,我们判断数据是否存在和是否正在加载中。如果有错误,我们抛出错误。最后,我们手动映射返回的数据,将 "age" 转换为 number 类型。
这种方法的优点是灵活,可以根据需要对返回的数据进行任何处理。缺点是需要手动编写映射逻辑,并且可能会造成冗余代码。
2. 使用类型转换库
第二种解决方案是使用类型转换库。这种库可以自动将 JSON 数据转换为 JavaScript 类型,并且支持与 TypeScript 或 Flow 等类型检查器集成。比如,我们可以使用 json-typescript-mapper
这个库,定义一个映射配置:
-- -------------------- ---- ------- ------ - ------------ ----------------- - ---- ------------------ --------- ---- - ----- ------- ---- ------- - ----- ----------- - --- -------------- --------------------------------- - ------ ----------------------------- - ----------------------------- ------------------------- - ------- - ---- ------- ------- -- -------------- -- ---
在这个配置中,我们定义了一个 User
类型和一个 JsonConvert
实例。首先,我们将 ignorePrimitiveChecks
设为 false,这样可以确保每个变量都有明确的类型。然后,我们将 valueCheckingMode
设为 ALLOW_NULL
,这样我们可以处理一些可能为 null 的变量。最后,我们定义了一个 User
类型的映射,将 "age" 属性映射为一个数字类型的值。
有了这个映射配置之后,我们就可以使用它将返回的数据转换为我们定义的类型了:
-- -------------------- ---- ------- ------ - --------- --- - ---- ----------------- ------ - ----------- - ---- ---------------- ------ - ---- - ---- ---------- ------ -------- --------- - ----- - -------- ------ ---- - - ------------- ----- ------- - ---- - ---- --- - - --- -- ------- - ----- ------ - -- -------- -- ------ - ------ ----- - ----- - ---- - - ----- ------ ----------------------------------- ------ -
在这个钩子中,我们首先使用 useQuery
获取数据,然后判断数据是否存在和是否正在加载中。如果有错误,我们抛出错误。最后,我们使用 jsonConvert
将返回的数据转换为我们定义的 User
类型。
这种方法的优点是自动化程度高,并且可以避免冗余代码。缺点是需要使用第三方库,可能会增加项目的依赖。此外,这种方法不能完全取代手动映射的方法,因为有些数据可能需要特殊处理。
结论
GraphQL 在 JavaScript 中的类型不匹配问题是一个常见的问题。我们可以使用手动映射或者类型转换库等方法来解决这个问题。手动映射方法灵活但可能会冗余代码,类型转换库则可以自动化程度高但需要使用第三方库。在实际开发中,我们可以选择最适合自己项目的方法,来处理这个问题。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/674802475883fc5ebfef0838