3

这里是 typescript + redux 生态系统的新手。

在 TypeScript 中使用 redux-actions、redux-thunk 和 redux-promise-middleware 时,如何将类型信息正确封装到异步操作中?

身份验证示例:

/* actions */
const login = createAction(LOGIN, authService.login);


/* authService */
async function login(payload: LoginPayload): Promise<LoginResponse> {
 // ... authenticate here.
}

由于我使用的是 redux-promise-middleware,因此会自动分派actions LOGIN_PENDINGLOGIN_FULFILLED/ 。LOGIN_REJECTED我如何为这些创建类型,以便减速器可以找出它正在处理的操作对象?

由于 redux-actions 遵循 FSA,_FULFILLED所以应该有action.payload. _REJECTED应该有action.error

/* reducer */
function loginReducer(state: AppState, action: AuthAction) {
  switch (action.type) {
    case LOGIN_FULFILLED:
      // action.payload should be defined as LoginResponse object here.
      // action.error shouldnt be present.
    case LOGIN_REJECTED:
      // action.error should be defined
  }
}

我将如何创建AuthAction类型?我猜它应该是每个单独动作类型的联合类型(可以是它们自己的联合类型)。redux-actions也为此提供ActionBaseAction类型。

4

2 回答 2

0

执行此操作的“正常”方法是指定所有“操作接口”和一个联合类型,直到减速器。然后打开类型。但是从示例代码中不清楚 AuthAction 类型是否是联合类型......

例如

type T = Object; //Your resolve data type
interface ILoginAction {type: "LOGIN", payload: {promise: Promise<T> }}
interface ILoginRejectedAction {type: "LOGIN_REJECTED", error: YourErrorType }
interface ILoginFulfilledAction {type: "LOGIN_FULFILLED", payload: {data: T }}

export type LoginActions = ILoginAction | ILoginRejectedAction | ILoginFulfilledAction

减速器:

import { LoginActions } from "./actions"; //Or where your actions are
function loginReducer(state: AppState, action: LoginActions) {
  switch (action.type) {
    case "LOGIN":
      // action.payload should be defined as LoginResponse object here.
      // action.error shouldnt be present.
    case "LOGIN_REJECTED":
      // action.error should be defined
  }
}

您可能可以使用一些泛型以更智能的方式创建此联合,但这是手动方法。

于 2017-10-18T11:14:29.097 回答
0

我建议使用createAsyncAction而不是createAction. 这样,您可以按如下方式定义类型:

/* actions */
const login = createAsyncAction<
  typeof LOGIN,
  LoginResponse, // no need to wrap in Promise<>
  null, // this is optional Meta,
  [LoginPayload] // action creator arguments wrapped in array
>(LOGIN, authService.login);

但恐怕我没有关于什么时候login是重击的答案:

/* actions */
const loginAction = createAsyncAction(LOGIN, authService.login)
const loginActionCreator = (data: LoginPayload) => async(dispatch: Dispatch) => {
  await dispatch(loginAction(data));
}
// ERROR: () => void is not assignable to () => (dispatch) => void (pseudo code)
于 2019-12-20T15:00:40.750 回答