无法在 createAsyncThunk 中将 getState 类型设置为 RootState

11 typescript redux redux-thunk redux-toolkit

我无法设置getState()to的返回类型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;
  }
);
Run Code Online (Sandbox Code Playgroud)

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

Joã*_*aky 12

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;
  }
);
Run Code Online (Sandbox Code Playgroud)

定义state将自动使 getState 知道应用程序状态。

  • 谢谢您的回答。虽然这确实有效,但我仍然更喜欢 Linda Paiste 给出的答案。显式声明切片状态消除了“any”的使用。我的 typescript/eslint 规则不鼓励显式使用“any”。 (2认同)

Lin*_*ste 8

你真的不需要知道整个状态的形状。您只需要知道您尝试访问的值是否存在。

如果您可以访问整个state.meta类型:

const { meta } = getState() as { meta: MetaState };
Run Code Online (Sandbox Code Playgroud)

如果不:

const { meta } = getState() as { meta: { subscriptionId: string } };
Run Code Online (Sandbox Code Playgroud)

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


thS*_*oft 7

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


Eva*_*s B 6

最好的方法是在实用程序文件中的某个位置创建一个预键入的异步 thunk,如文档所示

export const createAppAsyncThunk = createAsyncThunk.withTypes<{
  state: RootState
  dispatch: AppDispatch
  rejectValue: string
  // extra: { s: string; n: number } // This is extra data prop, can leave it out if you are not passing extra data
}>()
Run Code Online (Sandbox Code Playgroud)

执行此操作后,您将在使用创建的所有 thunk 中自动拥有所有类型createAppAsyncThunk

所以在OP的例子中它看起来像这样:

export const unsubscribeMeta = createAppAsyncThunk (
  'meta/unsubscribe',
  async (_, { getState }) => {
    const { meta } = getState() // This is typed automatically 
    const res = await client.post<apiUnsubscribeResponse>(
      `/meta/unsubscribe/${meta.subscriptionId}`
    );
    return res.data.data;
  }
);
Run Code Online (Sandbox Code Playgroud)


Nea*_*arl 5

您可以使用 Typescript 的模块增强功能来分配默认状态AsyncThunkConfig.stategetState()当我们稍后调用它时将返回类型。

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>;
}
Run Code Online (Sandbox Code Playgroud)

YourRootState您的商店状态的类型在哪里。

type YourRootState = {
  myNumber: number;
  myString: string;
};
Run Code Online (Sandbox Code Playgroud)

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

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>;
}
Run Code Online (Sandbox Code Playgroud)

现场演示

编辑 64793504/cannot-set-getstate-type-to-rootstate-in-createasyncthunk


Ahm*_*med 5

我将继续 NearHuscarl 的答案,因为我无法建议对其进行编辑。

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

因此,只需options像下面这样设置 type 就可以解决这个问题。

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>;
}
Run Code Online (Sandbox Code Playgroud)