如何使用flowtype绑定异步操作创建者?

时间:2016-11-15 22:10:16

标签: javascript redux flowtype redux-thunk

我刚刚开始学习flowtype,我需要一些帮助来理解我脑海中不清楚的两件事。

  1. https://github.com/reactjs/redux/blob/master/examples/todos-flow为例,我想知道如果没有https://github.com/flowtype/flow-typed的类型定义,对类型的控制是如何工作的,在这种情况下:https://github.com/flowtype/flow-typed/blob/master/definitions/npm/redux_v3.x.x/flow_v0.33.x-/redux_v3.x.x.js

  2. 如果我使用redux定义,当我尝试绑定异步动作创建器(我正在使用redux-thunk)时,bindActionCreators的验证失败。

  3. 如何在使用redux-thunk时继续使用flow并绑定异步操作创建者?

    代码示例(https://gist.github.com/momsse/323c228e8c5e264067039b8446cd890f):

    import { bindActionCreators } from 'redux';
    import type { Dispatch } from 'redux';
    
    type Action = { type: 'SET_PROFILE', profile: Object };
    
    /**
     * Based on https://github.com/gaearon/redux-thunk/blob/master/index.d.ts
     */
    type ThunkAction = (dispatch: Dispatch<Action>,
                        getState: () => any,
                        extraArgument: any) => any;
    
    type Profile = {
      name: string,
      team: string
    }
    
    // Async actions creator
    function setProfile(profile: Profile): ThunkAction {
      return dispatch => setTimeout(() => dispatch({ type: 'SET_PROFILE', profile }), 2000);
    }
    
    const profileActionCreators = { setProfile };
    
    type Props = {
      actions: {
        setProfile: (profile: Profile) => ThunkAction,
      }
    }
    
    function mapDispatchToProps(dispatch: Dispatch<Action>): Props {
      return {
        actions: bindActionCreators(profileActionCreators, dispatch)
      };
    }
    

    错误:

     40:     actions: bindActionCreators(profileActionCreators, dispatch)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call. Function cannot be called on any member of intersection type
     40:     actions: bindActionCreators(profileActionCreators, dispatch)
                      ^^^^^^^^^^^^^^^^^^ intersection
      Member 1:
       49:   declare function bindActionCreators<A, C: ActionCreator<A, any>>(actionCreator: C, dispatch: Dispatch<A>): C;
                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ polymorphic type: function type. See lib: flow-typed/npm/redux_v3.x.x.js:49
      Error:
       49:   declare function bindActionCreators<A, C: ActionCreator<A, any>>(actionCreator: C, dispatch: Dispatch<A>): C;
                                                       ^^^^^^^^^^^^^^^^^^^^^ function type. Callable signature not found in. See lib: flow-typed/npm/redux_v3.x.x.js:49
       40:     actions: bindActionCreators(profileActionCreators, dispatch)
                                           ^^^^^^^^^^^^^^^^^^^^^ object literal
      Member 2:
       50:   declare function bindActionCreators<A, K, C: ActionCreators<K, A>>(actionCreators: C, dispatch: Dispatch<A>): C;
                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ polymorphic type: function type. See lib: flow-typed/npm/redux_v3.x.x.js:50
      Error:
       13:   declare type Dispatch<A: { type: $Subtype<string> }> = (action: A) => A;
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ property `type` of object type. Property not found in. See lib: flow-typed/npm/redux_v3.x.x.js:13
       21: function setProfile(profile: Profile): ThunkAction {
                                                  ^^^^^^^^^^^ function type
    

1 个答案:

答案 0 :(得分:0)

这些是ActionCreator和bindActionCreators的完整声明:

  declare type ActionCreator<A, B> = (...args: Array<B>) => A;
  declare type ActionCreators<K, A> = { [key: K]: ActionCreator<A, any> };

  declare function bindActionCreators<A, C: ActionCreator<A, any>>(actionCreator: C, dispatch: Dispatch<A>): C;
  declare function bindActionCreators<A, K, C: ActionCreators<K, A>>(actionCreators: C, dispatch: Dispatch<A>): C;

在您的代码中,bindActionCreators将在dispatch中包装profileActionCreators的每个属性。您似乎期望将调度传递给setProfile函数,其中dispatch稍后可以用作回调。

但在我看来,bindActionCreators支持&#34;绑定&#34;作为回调发送。相反,派遣是&#34;绑定&#34;像这样:

function bindActionCreator(actionCreator, dispatch) {
  return (...args) => dispatch(actionCreator(...args))
}

因此,在您的代码中,它实际上看起来像这样:

function mapDispatchToProps(dispatch: Dispatch<Action>): Props {
  return {
    actions: {
      setProfile: (profile) => dispatch(dispatch => setTimeout(() => dispatch({ type: 'SET_PROFILE', profile }), 2000)),
  };
}
因此,

Flowtype正确捕获类型错误,说bindActionCreators期望对象的每个属性都是actionCreator:() => Action

您可能无法将bindActionCreator用于您的用例,或者您需要重新考虑如何处理thunk。 Here is an approach that should work

const profileActionCreators = { setProfile };

type Props = {
  actions: {
    setProfile: (profile: Profile) => setTimeout,
  }
}

function mapDispatchToProps(dispatch: Dispatch<Action>): Props {
  const boundActions = bindActionCreators(
    profileActionCreators,
    dispatch
  );
  return ({
    actions: {
      setProfile: (profile: Profile) => setTimeout(() => boundActions.setProfile(profile), 2000),
    },
  });
}

Thunk方法

如果你想保持你的ThunkAction方法,你将无法使用bindActionCreators。 This also works.