You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为传递给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:03:01