如何为传递给redux-observable epic生成函数的typesafe-actions异步动作指定类型?
解决CreateAsyncAction类型丢失,让isActionOf和payload正确解析的方案
我来帮你搞定这个类型推断的问题——核心是要给createAsyncEpic的asyncAction参数指定带泛型的AsyncAction类型,明确请求、成功、失败三种action对应的payload类型,这样TypeScript就能完美识别isActionOf和action.payload的类型了。
具体步骤和代码示例:
首先,我们需要明确AsyncAction的泛型定义,它接收三个核心类型参数:RequestPayload(请求action的payload类型)、SuccessPayload(成功action的payload类型)、FailurePayload(失败action的payload类型),同时还要对应三个action的type字符串类型。
然后修改你的createAsyncEpic函数,给它加上泛型约束,同时指定asyncAction的正确类型:
import { Epic } from 'redux-observable'; import { AsyncAction, isActionOf } from 'typesafe-actions'; import { ApolloClient, ApolloError, ApolloQueryResult } from '@apollo/client'; // 假设你的RootAction和RootState已经提前定义 type RootAction = /* 你的所有action联合类型 */; type RootState = /* 你的全局状态类型 */; // 假设你有已初始化的ApolloClient实例 const client: ApolloClient<any> = /* 你的client实例 */; // 定义通用的createAsyncEpic函数,带三个泛型参数 const createAsyncEpic = <RequestPayload, SuccessPayload, FailurePayload = ApolloError>( asyncAction: AsyncAction< string, // REQUEST action的type字符串 RequestPayload, string, // SUCCESS action的type字符串 SuccessPayload, string, // FAILURE action的type字符串 FailurePayload >, mutation: any // 这里可以进一步细化为DocumentNode类型,提升类型安全性 ): Epic<RootAction, RootState> => { return (action$, state$) => action$.pipe( filter(isActionOf(asyncAction.request)), withLatestFrom(state$), mergeMap(([action, state]) => client .mutate<SuccessPayload>({ mutation, variables: { ...action.payload } // 此处payload自动推断为RequestPayload类型 }) .then((result: ApolloQueryResult<SuccessPayload>) => { return asyncAction.success(result.data); // success的payload类型匹配SuccessPayload }) .catch((error: FailurePayload) => { return asyncAction.failure(error); // failure的payload类型匹配FailurePayload }) ) ); };
关键说明:
- 给
createAsyncEpic添加泛型<RequestPayload, SuccessPayload, FailurePayload>,让函数能根据传入的具体asyncAction自动推断所有关联类型。 asyncAction的类型指定为AsyncAction<...>,其中前三个字符串类型对应REQUEST/SUCCESS/FAILURE的action type(如果你的createAsyncAction已经定义了具体type,也可以用typeof asyncAction.request.type这类方式直接引用,进一步增强类型绑定)。- 在
client.mutate里指定泛型<SuccessPayload>,确保返回的result.data类型和asyncAction.success的payload类型完全匹配。 - 这样处理后,
isActionOf(asyncAction.request)会精准过滤对应的请求action,action.payload也会被TypeScript自动推断为RequestPayload类型,彻底解决类型丢失的问题。
实际使用示例:
假设你用createAsyncAction创建了一个具体的异步action:
// 定义用户类型 type User = { id: string; name: string; email: string }; // 创建具体的异步action,明确各阶段payload类型 const fetchUser = createAsyncAction( 'FETCH_USER_REQUEST', 'FETCH_USER_SUCCESS', 'FETCH_USER_FAILURE' )<{ userId: string }, { user: User }, ApolloError>(); // 创建对应的epic const fetchUserEpic = createAsyncEpic(fetchUser, FETCH_USER_MUTATION);
此时fetchUserEpic里的action.payload会自动推断为{ userId: string },success的payload是{ user: User },完全符合类型要求,编辑器也会提供完整的类型提示。
内容的提问来源于stack exchange,提问作者user2966636
相关产品推荐
相关产品推荐

