Reputation: 1303
Prior to me joining my current team, a colleague implemented React Flow. In principle I like this idea because I fully appreciate the power of strongly typed languages.
However, it has become clear that React Flow is woefully lacking in sophistication and intelligence. For example, in order to comply with one of its common "errors", we would have to remove constants in our Actions & Reducers and instead use literal strings. This would be stepping backwards simply to comply with a tool that doesn't understand that its recommendations are worse than the approach used.
I'm thinking that others have come up across this situation. In our case, we were planning on having Flow as a "gatekeeper" for whether code would get merged or not. This will no longer work. So how have you dealt with this conundrum?
UPDATE: As per @Alex Savin's comment below, here's a tangible example of Flow's "limitations":
Actions:
// @flow
import type { SystemMessage } from '../SessionContext';
// Note: 'ActionType' is just a string
import type { ActionType } from '../../redux/FlowTypes';
export const UPDATE_SESSION_PROP: ActionType = 'UPDATE_SESSION_PROP';
export const ADD_SYSTEM_MESSAGE: ActionType = 'ADD_SYSTEM_MESSAGE';
export const CLEAR_SYSTEM_MESSAGE: ActionType = 'CLEAR_SYSTEM_MESSSAGE';
type UpdateSessionAction = {type: typeof UPDATE_SESSION_PROP,
propName: string,
payload: string | number};
type AddSystemMessageAction = {type: typeof ADD_SYSTEM_MESSAGE,
payload: SystemMessage};
type ClearSystemMessageAction = {type: typeof CLEAR_SYSTEM_MESSAGE};
export type SessionAction =
| UpdateSessionAction
| AddSystemMessageAction
| ClearSystemMessageAction;
Reducer:
// @flow
import type { SessionState } from '../SessionContext';
import type { SessionAction } from '../actions/Session';
import { UPDATE_SESSION_PROP,
ADD_SYSTEM_MESSAGE,
CLEAR_SYSTEM_MESSAGE } from '../actions/Session';
export const sessionReducer = (state: SessionState, action: SessionAction) => {
switch (action.type) {
case UPDATE_SESSION_PROP: {
return {
...state,
[action.propName]: action.payload
};
}
case ADD_SYSTEM_MESSAGE: {
return {
...state,
systemMessage: action.payload
}
}
case CLEAR_SYSTEM_MESSAGE: {
return {
...state,
systemMessage: {}
}
}
default: {
return state;
}
}
}
Sample Dispatch call:
dispatchSession({type: ADD_SYSTEM_MESSAGE, payload: {status, message}});
These are the errors being displayed by Flow:
Actions:
None
Reducer
The
propName
ofaction.propName
:Cannot get
action.propName
because propertypropName
is missing inAddSystemMessageAction
[1].Flow(InferError) Session.js(11, 61): [1]AddSystemMessageAction
Cannot getaction.propName
because propertypropName
is missing inClearSystemMessageAction
[1].Flow(InferError) Session.js(11, 61): [1]ClearSystemMessageAction
The
payload
of bothaction.payload
instances: ``` Cannot getaction.payload
because propertypayload
is missing inClearSystemMessageAction
[1].Flow(InferError) Session.js(11, 61): [1]ClearSystemMessageAction
The sample Dispatch call:
Could not decide which case to select, since case 2 [1] may work but if it doesn't case 3 [2] looks promising too. To fix add a type annotation to
status
[3].Flow(InferError) Session.js(29, 8): [1] case 2 Session.js(30, 8): [2] case 3 AddUsers.js(139, 62): [3] tostatus
Upvotes: 0
Views: 304
Reputation: 528
Why not type action types properly? Like this
export const UPDATE_SESSION_PROP: 'UPDATE_SESSION_PROP' = 'UPDATE_SESSION_PROP';
I understand that it's a bit repetitive, but you can try instruments like keymirrror to avoid repetition
Upvotes: 1