ownProps,mapStateToProps和mapDispatchToProps的react-redux流类型定义

问题描述 投票:1回答:1

我是使用flow的新手,因此我可能会犯一些非常愚蠢的错误。

我想创建一个Props流类型,该类型与传递给组件的props,从mapStateToProps返回的redux存储中获得的props和mapDispatchToProps上定义的一些动作创建者相交。

下面显示的所有代码均可在该流try上使用

让我们考虑一下以下状态和动作创建者:

国家与行动创造者

// State type
type State = {
    state_text: string,
    state_num: number,
}

// Action type
type Action = 
    | { type: 'ACTION_CREATOR_1', text: string}
    | { type: 'ACTION_CREATOR_2', value: number}


// action creators
const actionCreator_1 = (): Action => ({
    type: 'ACTION_CREATOR_1',
    text: 'some text',
})
const actionCreator_2 = (num: number): Action => ({
    type: 'ACTION_CREATOR_2',
    value: num + 1,
})

我按照这篇文章中的示例进行操作,然后使用类似以下的内容来定义我的类型:

道具类型定义

const mapStateToProps = (state: State) => {
    const { state_text, state_num } = state
    return { state_text, state_num }
}

const mapDispatchToProps = {
    actionCreator_1,
    actionCreator_2,
}


// type extract return helper
type _ExtractReturn<B, F: (...args: any[]) => B> = B
type ExtractReturn<F> = _ExtractReturn<*, F>


// set combined types 
type ReduxState = ExtractReturn<typeof mapStateToProps>

type ReduxActions = typeof mapDispatchToProps

type OwnProps = { 
    own_string: string,
    own_num: number 
}

type Props =  OwnProps & ReduxState & ReduxActions

有了这个定义,我期望道具是这样的:

type DesiredProp =   {|
    own_string: string,
    own_num: number,
    state_text: string,
    state_num: number,
    actionCreator_1: () => Action,
    actionCreator_2: (num: number) => Action,
|} 

但是,以下情况显示没有流错误:

const props2: Props = {
    own_string: 'text',                 // OK - gives error if 123  
    own_num: 123,                       // OK - gives error if 'text'
    state_text: 123,                    // NOK - should be an error     
    state_num: 'text',                  // NOK - should be an error 
    actionCreator_1: actionCreator_1,   // OK - gives error if actionCreator_2
    actionCreator_2: actionCreator_1,   // NOK - should be an error 
    fakeActionCreator: () => {}         // NOK - should be an error 
}

我将所有这些代码放入此流程中 ,以使其更易于理解和使用。

我如何才能找到想要的?

reactjs redux react-redux flowtype
1个回答
5
投票

好吧,看来您的帖子中有几件事主题,所以我将分解我的答案

返回不相交的工会会员

在这里,您将返回Action Disjoint联合的成员

// Action type
type Action = 
  | { type: 'ACTION_CREATOR_1', text: string}
  | { type: 'ACTION_CREATOR_2', value: number}

// action creators
const actionCreator_1 = (): Action => ({
  type: 'ACTION_CREATOR_1',
  text: 'some text',
})

const actionCreator_2 = (num: number): Action => ({
  type: 'ACTION_CREATOR_2',
  value: num + 1,
})

并且您希望它能够对这些行进行类型检查:

actionCreator_1: actionCreator_1,   // OK - gives error if actionCreator_2
actionCreator_2: actionCreator_1,   // NOK - should be an error 

事实是,您将动作创建者的返回类型都设置为Action ,因此,只要您的actionCreator_1 / 2属性之一返回Action ,代码就是正确的。 您需要在这里做的是使操作创建者的返回类型更具体:

type Action1 = { type: 'ACTION_CREATOR_1', text: string}
type Action2 = { type: 'ACTION_CREATOR_2', value: number}

// Action type
type Action = 
  | Action1
  | Action2

// action creators
const actionCreator_1 = (): Action1 => ({
  type: 'ACTION_CREATOR_1',
  text: 'some text',
})

const actionCreator_2 = (num: number): Action2 => ({
  type: 'ACTION_CREATOR_2',
  value: num + 1,
})

现在流程将抛出一个错误( try ):

    76:     actionCreator_2: actionCreator_1,   // NOK - should be an error 
                            ^ Cannot assign object literal to `props2` because property `value` is missing in `Action1` [1] but exists in `Action2` [2] in the return value of property `actionCreator_2`.
    References:
    18: const actionCreator_1 = (): Action1 => ({
                                    ^ [1]
    23: const actionCreator_2 = (num: number): Action2 => ({
                                               ^ [2]
    76:     actionCreator_2: actionCreator_1,   // NOK - should be an error 
                            ^ Cannot assign object literal to `props2` because string literal `ACTION_CREATOR_1` [1] is incompatible with string literal `ACTION_CREATOR_2` [2] in property `type` of the return value of property `actionCreator_2`.
    References:
    9: type Action1 = { type: 'ACTION_CREATOR_1', text: string}
                              ^ [1]
    10: type Action2 = { type: 'ACTION_CREATOR_2', value: number}
                               ^ [2]

确切地指定一个对象

现在,您要使用三个对象的交集来获取Props类型。 由于您正在使用不精确的对象(相交的结果),因此无法获得准确的结果。 首先,您需要精确调整您的OwnProps 。 然后,您需要组合所有对象。 我这样做与传播:

// set combined types 
type ReduxState = ExtractReturn<typeof mapStateToProps>
type ReduxActions = typeof mapDispatchToProps

// This object type needs to be exact
type OwnProps = {|
  own_string: string,
  own_num: number 
|}

// Use a spread to combine the exact objects into one
type Props =  {|
  ...OwnProps,
  ...ReduxState,
  ...ReduxActions,
|}

现在,它为那个讨厌的额外属性引发了一个错误( try ):

    74: const props2: Props = {                          ^ Cannot assign object literal to `props2` because property `fakeActionCreator` is missing in `Props` [1] but exists in object literal [2].
    References:
    74: const props2: Props = {
                      ^ [1]
    74: const props2: Props = {                          ^ [2]

提取类型干扰推理

不幸的是,我似乎ReduxState通过返回类型提取来理解ReduxState返回类型。 似乎认为是这样的:

type ReduxState = ExtractReturn<(state: State) => {|state_num: (string | number), state_text: (string | number)|}>

因此,它似乎正在合并您在props2对象中的props2和提取的类型信息的推断。 为了解决这个问题,我最好的建议是手动键入mapStateToProps函数的输出:

const mapStateToProps = (state: State): {|
    state_text: string,
    state_num: number,
|} => {
  const { state_text, state_num } = state
  return { state_text, state_num }
}

之后它应该抛出一个错误( Try

    80:     state_text: 123,                    // NOK - should be an error     
                     ^ Cannot assign object literal to `props2` because number [1] is incompatible with string [2] in property `state_text`.
    References:
    80:     state_text: 123,                    // NOK - should be an error     
                     ^ [1]
    34:     state_text: string,
                     ^ [2]
    81:     state_num: 'text',                  // NOK - should be an error 
                      ^ Cannot assign object literal to `props2` because string [1] is incompatible with number [2] in property `state_num`.
    References:
    81:     state_num: 'text',                  // NOK - should be an error 
                      ^ [1]
    35:     state_num: number,
                       ^ [2]
© www.soinside.com 2019 - 2024. All rights reserved.