2016-11-15 3 views
7

Я только начал изучать тип потока, и мне нужна помощь, чтобы понять две вещи, которые не ясны на мой взгляд.Как связать создателей асинхронных действий с использованием метода 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, проверка bindActionCreators терпит неудачу, когда я пытаюсь связать создателя действия async (я использую 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 

ответ

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 окутает каждое свойство профиляActionCreators в 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 для своего прецедента, или вам нужно переосмыслить, как вы справляетесь с thunks. 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.