Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flowtype: "object literal could not decide which case to select" when using constants in redux actions

EDIT: Here is a full GitHub repo of a minimal example that shows the issue.

I have a simple Counter app. Here are my action creators:

actions.js

/**
 * @flow
 */

import { INCREMENT, DECREMENT } from '../constants'

type Action =
  | { type: 'INCREMENT' }
  | { type: 'DECREMENT' }

function increment(): Action {
  return {
    type: INCREMENT
  }
}

function decrement(): Action {
  return {
    type: DECREMENT
  }
}

export { increment, decrement }
export type { Action }

Currently, I'm getting an error in both the increment and decrement functions which states that object literal Could not decide which case to select union type.

To fix these errors, I can change type: INCREMENT to type: 'INCREMENT' and change type: DECREMENT to type: 'DECREMENT'. However, I'm going to be using this constant in multiple places (like the reducer), so I was hoping to be able to just import the constant and use it there. Is this not the way it's done in flowtype?

For clarity, here are the rest of the files:

constants.js

/**
 * @flow
 */

const INCREMENT: 'INCREMENT' = 'INCREMENT'
const DECREMENT: 'DECREMENT' = 'DECREMENT'

export {
  INCREMENT,
  DECREMENT
}

reducer.js

/**
 * @flow
 */

import { INCREMENT, DECREMENT } from '../constants'
import type { Action } from '../actions'

type State = number

function counter(state: State = 0, action: Action): State {
  switch (action.type) {
    case INCREMENT:
      return state + 1

    case DECREMENT:
      return state - 1

    default:
      return state
  }
}

export default counter

Edit: Here is a detailed error log

src/actions/counter.js:12
              v
 12:   return {
 13:     type: INCREMENT
 14:   }
       ^ object literal. Could not decide which case to select
 11: function increment(): Action {
                           ^^^^^^ union type
  Case 1 may work:
    8:   | { type: 'INCREMENT' }
           ^^^^^^^^^^^^^^^^^^^^^ object type
  But if it doesn't, case 2 looks promising too:
    9:   | { type: 'DECREMENT' }
           ^^^^^^^^^^^^^^^^^^^^^ object type
  Please provide additional annotation(s) to determine whether case 1 works (or consider merging it with case 2):
   13:     type: INCREMENT
                 ^^^^^^^^^ identifier `INCREMENT`

src/actions/counter.js:18
              v
 18:   return {
 19:     type: DECREMENT
 20:   }
       ^ object literal. Could not decide which case to select
 17: function decrement(): Action {
                           ^^^^^^ union type
  Case 1 may work:
    8:   | { type: 'INCREMENT' }
           ^^^^^^^^^^^^^^^^^^^^^ object type
  But if it doesn't, case 2 looks promising too:
    9:   | { type: 'DECREMENT' }
           ^^^^^^^^^^^^^^^^^^^^^ object type
  Please provide additional annotation(s) to determine whether case 1 works (or consider merging it with case 2):
   19:     type: DECREMENT
                 ^^^^^^^^^ identifier `DECREMENT`
like image 858
Saad Avatar asked Jun 10 '17 17:06

Saad


1 Answers

Try to add typeof into you action declaration:

type Action = 
  | { type: typeof INCREMENT } 
  | { type: typeof DECREMENT }

try flow here

Also you can use $Keys

const ActionTypes = {
  INCREMENT: 'INCREMENT',
  DECREMENT: 'DECREMENT'
}

type Action = { type: $Keys<typeof ActionTypes> } 

this looks less verbose

additional info here: https://github.com/facebook/flow/issues/2377

like image 72
hemn Avatar answered Sep 24 '22 19:09

hemn