我是使用flow的新手,所以我可能会做一些非常愚蠢的错误。
我想创建一个Props流类型,它与传递给组件的props相交,从mapStateToProps返回的redux商店获取的props和mapDispatchToProps上定义的一些动作创建者。
以下所示的所有代码均可在此flow 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,
})
我在this帖子上关注了一个示例,我得到了类似下面的内容来定义我的类型:
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
根据这个定义,我期待Props是这样的:
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
}
我将所有这些代码放在flow try中,以便更容易理解和使用。
我如何实现我正在寻找的目标?
答案 0 :(得分:5)
好吧,看来你的帖子中有一些主题,所以我打破了我的答案
此处您正在返回Action
disjoint union
// 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
的返回类型。它似乎认为是这样的:
type ReduxState = ExtractReturn<(state: State) => {|state_num: (string | number), state_text: (string | number)|}>
所以它似乎正在合并你在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]