简体   繁体   English

在打字稿中使用 redux-actions、redux-thunk 和 redux-promise-middleware

[英]Using redux-actions, redux-thunk and redux-promise-middleware in typescript

New to typescript + redux ecosystem here.这里是 typescript + redux 生态系统的新手。

How do I properly encapsulate type information into async actions when using redux-actions, redux-thunk and redux-promise-middleware in TypeScript?在 TypeScript 中使用 redux-actions、redux-thunk 和 redux-promise-middleware 时,如何将类型信息正确封装到异步操作中?

An example of authentication:身份验证示例:

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


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

Since I'm using redux-promise-middleware, the actions LOGIN_PENDING , LOGIN_FULFILLED / LOGIN_REJECTED are dispatched automatically.由于我使用的是 redux-promise-middleware,操作LOGIN_PENDINGLOGIN_FULFILLED / LOGIN_REJECTED是自动分派的。 How do I create types for these such that the reducer can figure out what action object it's dealing with?我如何为这些创建类型,以便 reducer 可以找出它正在处理的操作对象?

Since redux-actions follows FSA, _FULFILLED should have action.payload .由于 redux-actions 遵循 FSA, _FULFILLED应该有action.payload _REJECTED should have action.error _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
  }
}

How would I go about creating the AuthAction type?我将如何创建AuthAction类型? I'm guessing it should be a union type of each of the individual action types (which can be union types on their own).我猜它应该是每个单独的动作类型的联合类型(它们可以是自己的联合类型)。 redux-actions also provides Action and BaseAction types for this. redux-actions还为此提供了ActionBaseAction类型。

The "normal" way to do it is to specify all "action interfaces" and a union type down to the reducer. “正常”的方法是指定所有“操作接口”和一个联合类型,直到减速器。 Then switch on the type.然后打开类型。 But from the example code its not clear if the AuthAction type is a union type...但是从示例代码中不清楚 AuthAction 类型是否是联合类型......

eg例如

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

Reducer:减速机:

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
  }
}

You can probably create this union in a smarter way using some generics but this is the manual approach.您可以使用一些泛型以更智能的方式创建此联合,但这是手动方法。

I would recommend using createAsyncAction instead of createAction .我建议使用createAsyncAction而不是createAction That way you can define the typings as follows:这样你就可以定义类型如下:

/* 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);

But i'm afraid I don't have an answer for when login is a thunk:但恐怕我没有答案何时login是一个 thunk:

/* 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM