已配置dataIdFromObject的Apollo Client中,能否弃用GraphQL的ID标量类型?
当然可以完全不用GraphQL的ID标量类型!
你的场景下,因为MySQL主键是int类型,而GraphQL的ID标量默认会序列化为字符串,导致TypeScript类型冲突,完全抛弃ID改用Int是非常合理的解决方案,下面是具体的实现步骤和注意事项:
1. 修改GraphQL Schema定义
直接把原来的ID类型替换成Int,保持和MySQL主键类型一致:
type User { id: Int! # 替换ID为Int name: String! }
如果有其他关联类型(比如Post关联User),也要同步调整关联字段的类型,比如:
type Post { id: Int! title: String! authorId: Int! author: User! }
2. 调整Resolver逻辑
确保从MySQL查询返回的id以数字类型直接返回,不要做字符串转换。比如你的User resolver:
const resolvers = { Query: { user: async (_, { id }, { db }) => { const user = await db.query('SELECT id, name FROM users WHERE id = ?', [id]); return user[0]; // 直接返回数据库的int类型id }, }, };
3. 更新Apollo Client的dataIdFromObject
你已经在使用这个函数生成缓存唯一标识,现在只需要确保它能正确处理数字类型的id即可——因为Apollo Client的缓存键最终是字符串,所以直接拼接类型名和数字id完全没问题:
const dataIdFromObject = (obj) => { if (obj.__typename && obj.id !== undefined) { // 数字id会自动转为字符串拼接,不影响缓存键的唯一性 return `${obj.__typename}:${obj.id}`; } return null; };
4. 同步前端TypeScript类型
现在可以定义和GraphQL返回完全匹配的TS类型,彻底解决类型冲突:
type User = { id: number; // 用number对应Int类型 name: string; }; // 如果用Apollo Codegen自动生成类型,只要schema改了,生成的类型也会自动变成number
注意事项
- 保持全链路类型一致:从数据库、GraphQL Schema、Resolver到前端TS类型,所有涉及主键的地方都用数字类型,避免混合使用
ID和Int导致新的类型问题。 - Mutation参数同步调整:如果有修改用户的Mutation,比如
updateUser(id: Int!, name: String!),要把参数里的ID也换成Int,确保前后端参数类型匹配。 - 缓存操作检查:使用
writeQuery、update等Apollo Client缓存API时,传入的id要确保是数字类型,避免和缓存中已有的键不匹配。
这样调整后,你就完全摆脱了ID标量带来的字符串/数字类型冲突问题,同时Apollo Client的缓存功能依然能正常工作,因为dataIdFromObject生成的缓存键依然是唯一的。
内容的提问来源于stack exchange,提问作者RedGiant
相关产品推荐
相关产品推荐

