typescript thunkAPI.getState方法无法正确推断状态类型

dwbf0jvd  于 2022-12-24  发布在  TypeScript
关注(0)|答案(4)|浏览(148)

此处代码:
users.slice.ts

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

const userAPI = {
  async fetchById(userId: string) {
    return { data: { id: userId, name: 'teresa teng' } };
  },
};

export const fetchUserById = createAsyncThunk<User, string>(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    const response = await userAPI.fetchById(userId);
    return response.data;
  },
  {
    condition: (userId, { getState }) => {
      const { users } = getState();
      const { fetchStatus } = users[userId];
      if (fetchStatus === 'loading') {
        return false;
      }
    },
  }
);

interface User {
  name: string;
  id: string;
}

interface UsersSliceState {
  [id: string]: { fetchStatus: 'idle' | 'loading'; data: User };
}

const usersSliceState: UsersSliceState = {
  1: {
    fetchStatus: 'idle',
    data: { name: '', id: '' },
  },
};

const usersSlice = createSlice({
  name: 'users',
  initialState: usersSliceState,
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(fetchUserById.fulfilled, (state, action) => {
      console.log(action);
    });
  },
});

export default usersSlice.reducer;

store.ts

import { configureStore } from '@reduxjs/toolkit';
import usersSliceReducer from './users.slice';

export const store = configureStore({
  reducer: {
    users: usersSliceReducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;

main.ts

import { store } from './store';
import { fetchUserById } from './users.slice';

store.dispatch(fetchUserById('1'));

当我调用getState()方法并解构condition函数内的users状态切片时,TSC抛出错误
类型"{}"上不存在属性"users"。ts(2339)
推断的RootState类型为:

type RootState = {
    users: UsersSliceState;
}

我应该如何正确地创建这个类型?如果我导入RootState类型并对getState()的返回值进行类型转换,是否会导致循环引用?
软件包版本:

"@reduxjs/toolkit": "^1.5.0",
"typescript": "^4.1.2"
vmpqdwk3

vmpqdwk31#

您需要将createAsyncThunk中的state指定为RootState,其中state是用于定义thunkApi字段类型的可选字段的一部分。

export const fetchUserById = createAsyncThunk<
 User,
 string, 
 { state: RootState}
>(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    const response = await userAPI.fetchById(userId);
    return response.data;
  },
  {
    condition: (userId, { getState }) => {
      const { users } = getState();
      const { fetchStatus } = users[userId];
      if (fetchStatus === 'loading') {
        return false;
      }
    },
  }
);
kyxcudwk

kyxcudwk2#

为了避免循环依赖,像这样的东西怎么样?
代替

createAsyncThunk<User, string>

用途

createAsyncThunk<User, string, {state: {users: UserSliceState}}>
w80xi6nr

w80xi6nr3#

@types/react-redux中定义useSelector钩子的类型化别名(TypedUseSelectorHook)的方法似乎也可以用在这种情况下:

type TypedCreateAsyncThunk<ThunkApiConfig> = <Returned, ThunkArg = void>(
  typePrefix: string,
  payloadCreator: AsyncThunkPayloadCreator<Returned, ThunkArg, ThunkApiConfig>,
  options?: AsyncThunkOptions<ThunkArg, ThunkApiConfig>
) => AsyncThunk<Returned, ThunkArg, ThunkApiConfig>;

export const createAppAsyncThunk: TypedCreateAsyncThunk<{
  state: RootState;
}> = createAsyncThunk;
w8rqjzmb

w8rqjzmb4#

根据前面的回答,以下方法在我的情况下可以正常工作:
我们传入createAsyncThunk这些类型变量:

  1. type-for-result:完成操作时返回的类型(参见try块)
  2. type-for-datacreateAsyncThunk函数的第二个参数的第一个参数的类型
  3. ThunkApiConfig:这里,因为我们需要另一个状态的信息,我们需要告诉Typescript状态是RootState,这样我们就可以用getState()获取信息。此外,我们还可以添加type-for-message作为操作被拒绝时返回的消息(参见catch块)。
export const method = createAsyncThunk<
  type-for-result,
  type-for-data,
  { state: RootState, rejectValue: type-for-message }
>(
  'name',
  async (data, thunk) => { 
    try {
      const something = thunk.getState().someState.someProperty;
      // do something
      return result;
     } catch (error) {
      // do something
      return thunk.rejectWithValue(message);
     }
  })

package.json

"@reduxjs/toolkit": "^1.9.1",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/node": "^16.18.8",
    "@types/react": "^18.0.26",
    "@types/react-dom": "^18.0.9",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-icons": "^4.7.1",
    "react-redux": "^8.0.5",
    "react-router-dom": "6.4.5",
    "react-scripts": "5.0.1",
    "typescript": "^4.9.4",
    "web-vitals": "^2.1.4"

相关问题