robertwerner_sf
robertwerner_sf

Reputation: 1303

False Positives with React Flow

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 of action.propName:

Cannot get action.propName because property propName is missing in AddSystemMessageAction [1].Flow(InferError) Session.js(11, 61): [1] AddSystemMessageAction Cannot get action.propName because property propName is missing in ClearSystemMessageAction [1].Flow(InferError) Session.js(11, 61): [1] ClearSystemMessageAction

The payload of both action.payload instances: ``` Cannot get action.payload because property payload is missing in ClearSystemMessageAction [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] to status

Upvotes: 0

Views: 304

Answers (1)

Alex Savin
Alex Savin

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

Related Questions