【问题标题】:How to type function with generic async thunk as parameter?如何使用通用异步 thunk 作为参数键入函数?
【发布时间】:2023-02-01 01:14:43
【问题描述】:

我无法获得正确的类型以将异步 thunk 作为函数的参数传递并传播其 3 个关联的泛型类型,以便在调用函数时可以推断出它们。

我在文档中找不到任何关于如何处理这个问题的方法或解释。除了打字,下面的示例在应用程序中按预期工作(公司代码,无法共享)。

我的具体用例是我想要一个函数,它接受两个 thunk 并创建一个新的 thunk 来调度它们,结合参数。

const chainAsyncThunks = <
  FirstReturned,
  FirstThunkArg,
  FirstThunkApiConfig extends {},
  SecondReturned,
  SecondThunkArg,
  SecondThunkApiConfig extends {},
>(
  prefix: string,
  thunk1: AsyncThunk<FirstReturned, FirstThunkArg, FirstThunkApiConfig>,
  thunk2: AsyncThunk<SecondReturned, SecondThunkArg, SecondThunkApiConfig>,
) => {
  return createAsyncThunk('chained/' + prefix, async (arg: FirstThunkArg & SecondThunkArg, thunkAPI) => {
    const initialState = thunkAPI.getState() as RootState;
    try {
      await thunkAPI.dispatch(thunk1(arg)).unwrap();
    } catch (rejectedResult) {
      thunkAPI.dispatch(setRootState(initialState));
      throw rejectedResult;
    }
    try {
      await thunkAPI.dispatch(thunk2(arg)).unwrap();
    } catch (rejectedResult) {
      thunkAPI.dispatch(setRootState(initialState));
      throw rejectedResult;
    }
  });
};

我得到这个长的,看似不可读的错误。

TS2769: No overload matches this call.
  Overload 1 of 3, '(thunkAction: ThunkAction<Promise<PayloadAction<FirstReturned, string, { arg: FirstThunkArg; requestId: string;
 requestStatus: "fulfilled"; }, never> | PayloadAction<...>> & { ...; }, unknown, unknown, AnyAction>): Promise<...> & { ...; }', gave the following error.
    Argument of type 'AsyncThunkAction<FirstReturned, FirstThunkArg, FirstThunkApiConfig>' is not assignable to parameter of type '
ThunkAction<Promise<PayloadAction<FirstReturned, string, { arg: FirstThunkArg; requestId: string; requestStatus: "fulfilled"; }, ne
ver> | PayloadAction<GetRejectValue<...> | undefined, string, { ...; } & (({ ...; } & { [K in keyof GetRejectedMeta<...>]?: undefined; }) | ({ ...; } & GetRejectedMeta<...>)), GetSeriali...'.
      Types of parameters 'dispatch' and 'dispatch' are incompatible.
        Type 'ThunkDispatch<unknown, unknown, AnyAction>' is not assignable to type 'GetDispatch<FirstThunkApiConfig>'.
  Overload 2 of 3, '(action: AnyAction): AnyAction', gave the following error.
    Argument of type 'AsyncThunkAction<FirstReturned, FirstThunkArg, FirstThunkApiConfig>' is not assignable to parameter of type 'AnyAction'.
  Overload 3 of 3, '(action: AnyAction | ThunkAction<Promise<PayloadAction<FirstReturned, string, { arg: FirstThunkArg; requestId: 
string; requestStatus: "fulfilled"; }, never> | PayloadAction<...>> & { ...; }, unknown, unknown, AnyAction>): AnyAction | (Promise<...> & { ...; })', gave the following error.
    Argument of type 'AsyncThunkAction<FirstReturned, FirstThunkArg, FirstThunkApiConfig>' is not assignable to parameter of type '
AnyAction | ThunkAction<Promise<PayloadAction<FirstReturned, string, { arg: FirstThunkArg; requestId: string; requestStatus: "fulfilled"; }, never> | PayloadAction<...>> & { ...; }, unknown, unknown, AnyAction>'.
      Type 'AsyncThunkAction<FirstReturned, FirstThunkArg, FirstThunkApiConfig>' is not assignable to type 'ThunkAction<Promise<Pay
loadAction<FirstReturned, string, { arg: FirstThunkArg; requestId: string; requestStatus: "fulfilled"; }, never> | PayloadAction<Ge
tRejectValue<...> | undefined, string, { ...; } & (({ ...; } & { [K in keyof GetRejectedMeta<...>]?: undefined; }) | ({ ...; } & GetRejectedMeta<...>)), GetSeriali...'.
    19 |     const initialState = thunkAPI.getState() as RootState;
    20 |     try {
  > 21 |       await thunkAPI.dispatch(thunk1(arg)).unwrap();
      Type 'AsyncThunkAction<SecondReturned, SecondThunkArg, SecondThunkApiConfig>' is not assignable to type 'ThunkAction<Promise<PayloadAction<SecondReturned, string, { arg: SecondThunkArg; requestId: string; requestStatus: "fulfilled"; }, never> | PayloadAction<...>> & { ...; }, unknown, unknown, AnyAction>'.
    25 |     }
    26 |     try {
  > 27 |       await thunkAPI.dispatch(thunk2(arg)).unwrap();
       |                               ^^^^^^^^^^^
    28 |     } catch (rejectedResult) {
    29 |       thunkAPI.dispatch(setRootState(initialState));
    30 |       throw rejectedResult;

【问题讨论】:

    标签: typescript redux-toolkit redux-thunk


    【解决方案1】:

    有没有理由必须是asyncThunk?意思是:你对 pending/fulfilled/rejected 动作感兴趣吗?

    如果没有,只需编写一个普通的 thunk 函数:

    import { ThunkDispatch, AnyAction } from '@reduxjs/toolkit'
    
    function buildCombinedThunk<Arg>(thunk1: (arg: Arg) => ThunkAction<{unwrap: () => Promise<any>}, RootState, unknown, AnyAction>, thunk2: (arg: Arg) => ThunkAction<{unwrap: () => Promise<any>}, RootState, unknown, AnyAction>) {
      return (arg: Arg) => async (dispatch: ThunkDispatch<unknown, unknown, AnyAction>, getState: () => RootState) => {
        const initialState = getState();
        try {
          await dispatch(thunk1(arg)).unwrap();
        } catch (rejectedResult) {
          dispatch(setRootState(initialState));
          throw rejectedResult;
        }
        try {
          await dispatch(thunk2(arg)).unwrap();
        } catch (rejectedResult) {
          dispatch(setRootState(initialState));
          throw rejectedResult;
        }
    
      }
    }
    

    一般来说:像这样编写高阶函数可能绝对是矫枉过正,当你真正需要它们时编写这些组合的 thunk 可能只是一个更好的主意 - 然后你还可以编写更多“合适”和更少通用的逻辑。

    【讨论】:

      猜你喜欢
      • 2021-12-11
      • 1970-01-01
      • 2020-06-28
      • 1970-01-01
      • 1970-01-01
      • 2017-04-17
      • 2021-07-16
      • 2023-02-19
      相关资源
      最近更新 更多