React Native中ApolloClient配置createUploadLink与WebSocketLink报错求助
我正在React Native应用中实现文件上传功能,打算使用createUploadLink替代传统的createHttpLink,但在配置Apollo Client时遇到了类型不兼容的错误。下面是我的当前配置代码:
import SInfo from "react-native-sensitive-info"; import Config from "react-native-config"; import { InMemoryCache, ApolloClient } from "apollo-boost"; import { createHttpLink } from "apollo-link-http"; import { createUploadLink } from "apollo-upload-client"; import { WebSocketLink } from "apollo-link-ws"; import { setContext } from "apollo-link-context"; import { getMainDefinition } from "apollo-utilities"; import { split } from "apollo-link"; let token: any; const getToken = async () => { if (token != null) { return token; } token = await SInfo.getItem("ACCESS_TOKEN", {}); return token; }; export const cache = new InMemoryCache(); // Create a WebSocket link: const wsLink = new WebSocketLink({ uri: Config.SUBSCRIPTION_SERVER, options: { reconnect: true, }, }); const httpLink = createHttpLink({ uri: Config.GRAPHQL_SERVER }); const uploadLink = createUploadLink({ uri: Config.GRAPHQL_SERVER }); const authLink = setContext(async (_, { headers }) => { await getToken(); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : null, }, }; }); const linkConcated = authLink.concat(httpLink); // using the ability to split links, you can send data to each link // depending on what kind of operation is being sent const link = split( // split based on operation type ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === "OperationDefinition" && definition.operation === "subscription" ); }, wsLink, linkConcated ); export const client = new ApolloClient({ link, cache, });
尝试替换createHttpLink为createUploadLink,以及尝试用ApolloLink.from()组合链接后,都出现了以下TypeScript错误:
const uploadLink: ApolloLink Argument of type 'ApolloLink' is not assignable to parameter of type 'ApolloLink | RequestHandler'. Type 'import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink' is not assignable to type 'import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/apollo-link/lib/link").ApolloLink'. Types of property 'split' are incompatible. Type '(test: (op: import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/@apollo/client/link/core/types").Operation) => boolean, left: import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/home/musayyab/Desktop/projects/Ta...' is not assignable to type '(test: (op: import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/apollo-link/lib/types").Operation) => boolean, left: import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/apollo-link/lib/link").ApolloLink | import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node...'. Types of parameters 'test' and 'test' are incompatible. Types of parameters 'op' and 'op' are incompatible. Property 'toKey' is missing in type 'import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/@apollo/client/link/core/types").Operation' but required in type 'import("/home/musayyab/Desktop/projects/Talent/Native-App/app/node_modules/apollo-link/lib/types").Operation'.ts(2345) types.d.ts(24, 5): 'toKey' is declared here.
问题原因
这个错误是由于依赖版本不匹配导致的类型冲突:你项目中同时存在@apollo/client(新版)和旧版的apollo-link相关包,两者的ApolloLink类型定义不兼容,尤其是Operation类型的toKey属性差异。
解决步骤
统一依赖版本
确保你使用的apollo-upload-client版本与@apollo/client兼容。对于@apollo/client v3.x,需要安装apollo-upload-client@^16.0.0及以上版本:npm install apollo-upload-client@latest # 或者使用yarn yarn add apollo-upload-client@latest同时,移除旧的
apollo-link相关包(这些功能已集成到@apollo/client中,无需单独安装):npm uninstall apollo-link apollo-link-http apollo-link-ws apollo-link-context # yarn yarn remove apollo-link apollo-link-http apollo-link-ws apollo-link-context修正Apollo Client配置代码
用@apollo/client提供的工具替代旧包,并且只保留createUploadLink作为HTTP链接(它完全兼容普通GraphQL请求,同时支持文件上传):import SInfo from "react-native-sensitive-info"; import Config from "react-native-config"; import { InMemoryCache, ApolloClient, split, ApolloLink } from "@apollo/client"; import { createUploadLink } from "apollo-upload-client"; import { WebSocketLink } from "@apollo/client/link/ws"; import { setContext } from "@apollo/client/link/context"; import { getMainDefinition } from "@apollo/client/utilities"; let token: any; const getToken = async () => { if (token != null) { return token; } token = await SInfo.getItem("ACCESS_TOKEN", {}); return token; }; export const cache = new InMemoryCache(); // WebSocket链接用于订阅 const wsLink = new WebSocketLink({ uri: Config.SUBSCRIPTION_SERVER, options: { reconnect: true, connectionParams: async () => { await getToken(); return { authorization: token ? `Bearer ${token}` : null, }; }, }, }); // 使用createUploadLink替代createHttpLink const uploadLink = createUploadLink({ uri: Config.GRAPHQL_SERVER, }); // 认证链接 const authLink = setContext(async (_, { headers }) => { await getToken(); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : null, }, }; }); // 组合认证链接和上传链接 const httpAuthLink = authLink.concat(uploadLink); // 根据操作类型拆分链接:订阅用WS,其他用HTTP(uploadLink) const link = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === "OperationDefinition" && definition.operation === "subscription" ); }, wsLink, httpAuthLink ); export const client = new ApolloClient({ link, cache, });验证配置
重启TypeScript服务和React Native开发服务器,确保类型错误消失。此时你可以在GraphQL mutations中使用File类型的变量来实现文件上传了。
关键说明
createUploadLink是createHttpLink的超集,支持所有普通GraphQL请求的同时,还能处理multipart/form-data类型的文件上传请求,所以不需要同时保留createHttpLink。- 所有链接相关的工具都从
@apollo/client导入,彻底避免了旧版apollo-link包的类型冲突。
内容的提问来源于stack exchange,提问作者Musayyab Naveed

