Как связать создателей асинхронных действий с помощью 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.xx/flow_v0.33.x-/redux_v3.xxjs?

  2. Если я использую определения redux, проверка bindActionCreators завершается ошибкой, когда я пытаюсь привязать создателя асинхронного действия (я использую redux-thunk).

Как продолжить использование создателей потоковых и привязанных асинхронных действий при использовании redux-thunk?

Пример кода (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

person momsse    schedule 15.11.2016    source источник


Ответы (1)


Это полные объявления для 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 обернет каждое свойство profileActionCreators в dispatch. Похоже, вы ожидаете, что отправка будет передана в функцию setProfile, где отправку можно будет позже использовать в качестве обратного вызова.

Но мне не кажется, что bindActionCreators поддерживает отправку «привязки» в качестве обратного вызова. Скорее, отправка "привязана" следующим образом:

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.

Вероятно, вы не можете использовать bindActionCreators для своего варианта использования или вам нужно переосмыслить, как вы обрабатываете преобразователи. Вот подход, который должен работать.

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. person thejohnbackes    schedule 14.03.2017