【问题标题】:Cannot set getState type to RootState in createAsyncThunk无法在 createAsyncThunk 中将 getState 类型设置为 RootState
【发布时间】:2021-02-23 20:14:38
【问题描述】:

我无法将getState() 的返回类型设置为RootState。我正在使用打字稿和 VSCode。我必须将类型设置为any,这会停止该对象上的 IntelliSense。下面是有问题的代码:

export const unsubscribeMeta = createAsyncThunk(
  'meta/unsubscribe',
  async (_, { getState }) => {
    const { meta } = getState() as any;
    const res = await client.post<apiUnsubscribeResponse>(
      `/meta/unsubscribe/${meta.subscriptionId}`
    );
    return res.data.data;
  }
);

如果我尝试使用RootState 而不是any,VSCode 会在模块中标记许多错误。我相信这是由于商店和这个切片的循环依赖。我在模块中更下方的许多地方使用RootState 用于选择器,没有问题。有没有办法解决这个问题?

【问题讨论】:

    标签: reactjs typescript redux redux-thunk redux-toolkit


    【解决方案1】:

    我将继续使用 NearHuscarl 的答案,因为我无法建议对其进行修改。

    NearHuscarl 的答案很好,但问题在于他将options 类型设置为any,因此它解决了从现在开始如果您在createAsyncThunk 中使用options 会引发的另一个问题,您必须设置所有手动或typescript 将引发Binding element implicitly has an 'any' type. 错误。

    所以像下面这样简单地设置options 类型就可以解决这个问题。

    declare module "@reduxjs/toolkit" {
        type AsyncThunkConfig = {
            state?: unknown;
            dispatch?: Dispatch;
            extra?: unknown;
            rejectValue?: unknown;
            serializedErrorType?: unknown;
        };
    
        function createAsyncThunk<
            Returned,
            ThunkArg = void,
            ThunkApiConfig extends AsyncThunkConfig = { state: RootState } // here is the magic line
        >(
            typePrefix: string,
            payloadCreator: AsyncThunkPayloadCreator<
                Returned,
                ThunkArg,
                ThunkApiConfig
            >,
            options?: AsyncThunkOptions<ThunkArg, ThunkApiConfig>,
        ): AsyncThunk<Returned, ThunkArg, ThunkApiConfig>;
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用 Typescript 的 module augmentation 功能将默认状态分配给 AsyncThunkConfig.state,这将是我们稍后调用它时返回的 getState() 类型。

      declare module "@reduxjs/toolkit" {
        type AsyncThunkConfig = {
          state?: unknown;
          dispatch?: Dispatch;
          extra?: unknown;
          rejectValue?: unknown;
          serializedErrorType?: unknown;
        };
      
        function createAsyncThunk<
          Returned,
          ThunkArg = void,
          ThunkApiConfig extends AsyncThunkConfig = {
            state: YourRootState; // this line makes a difference
          }
        >(
          typePrefix: string,
          payloadCreator: AsyncThunkPayloadCreator<
            Returned,
            ThunkArg,
            ThunkApiConfig
          >,
          options?: any
        ): AsyncThunk<Returned, ThunkArg, ThunkApiConfig>;
      }
      

      其中YourRootState 是您的商店状态的类型。

      type YourRootState = {
        myNumber: number;
        myString: string;
      };
      

      现在您可以照常使用createAsyncThunkgetState() 返回正确的类型。

      const doSomethingAsync = createAsyncThunk(
        "mySlice/action",
        async (_, { getState, dispatch }) => {
          const rootState = getState(); // has type YourRootState
      
          console.log(rootState.myNumber);
          console.log(rootState.myString);
        }
      );
      
      
      function Child() {
        const dispatch = useDispatch();
        return <button onClick={() => dispatch(doSomethingAsync())}>Click</button>;
      }
      

      现场演示

      【讨论】:

      • 谢谢,这很好用。如果你不知道在哪里粘贴这段代码sn-p。只需将其粘贴到您声明根状态等的文件中
      【解决方案3】:

      createAsyncThunk 可以具有泛型上定义的类型:

      export const unsubscribeMeta = createAsyncThunk<apiUnsubscribeResponse, void, {state: RootState }>(
        'meta/unsubscribe',
        async (_, { getState }) => {
          const { meta } = getState();
          const res = await client.post<apiUnsubscribeResponse>(
            `/meta/unsubscribe/${meta.subscriptionId}`
          );
          return res.data.data;
        }
      );
      

      定义state 会自动让getState 知道应用程序的状态。

      【讨论】:

      • 感谢您的回答。虽然这确实有效,但我仍然更喜欢 Linda Paiste 给出的答案。显式声明切片状态消除了“any”的使用。我的 typescript/eslint 规则不鼓励明确使用“any”。
      【解决方案4】:

      只需从您的ThunkApiConfig 类型中省略state: RootState,然后您就可以在您的payloadCreator 中使用const state = getState() as RootState; 而无需循环依赖。

      【讨论】:

      • 无论如何我都不是 Redux 专家。我只使用 Redux 几个月,而且我只使用工具包。我在 Redux 工具包文档中找不到任何与 ThunkApiConfig 相关的文档。但是,我可能会坚持 Linda Paiste 提供的解决方案。我喜欢明确声明切片状态,而不是通过初始值暗示它。
      【解决方案5】:

      您实际上并不需要了解整个状态的形状。您只需要知道您尝试访问的值是否存在。

      如果您可以访问整个state.meta,请输入:

      const { meta } = getState() as { meta: MetaState };
      

      如果没有:

      const { meta } = getState() as { meta: { subscriptionId: string } };
      

      我推荐这种避免循环依赖的方法,因为根状态总是依赖于切片,所以切片不应该依赖于根。

      【讨论】:

      • 完美。谢谢。
      • 如果您不需要将整个商店传递给选择器,则此方法有效。否则需要使用根状态。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-11
      • 2017-09-23
      • 1970-01-01
      相关资源
      最近更新 更多