我是使用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
}
我将所有这些代码放入此流程中 ,以使其更易于理解和使用。
我如何才能找到想要的?
好吧,看来您的帖子中有几件事主题,所以我将分解我的答案
在这里,您将返回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]