const all = (...preds) => (obj) => preds.map(f => f(obj)).reduce((a, b) => a && b, true)
const any = (...preds) => (obj) => preds.map(f => f(obj)).reduce((a, b) => a || b, false)
const oneOf = (...preds) => (obj) => preds.map(f => f(obj)).reduce((a, b) => a ? !b : b, false)
const has = (prop) => (obj) => obj[prop] !== undefined
const not = (pred) => (obj) => !pred(obj)
const equals = (prop, val) => (obj) => obj[prop] === val
const implies = (f, g) => (obj) => !f(obj) || g(obj);

const validate = all(implies(has('selectedIndex'), equals('isOpen', true)))

validate({}) // true; passes all 'implications'
validate({'selectedIndex': 3}) // false; isOpen !== true!
validate({'selectedIndex': 3, isOpen: true}) // true; passes all implications


// more complex example
const complexValidate = all(
  implies(equals('mode', 'indexed'),
    all(
      has('selectedIndex'),
      obj => obj['selectedIndex'] <= 5
    )
  ),
  implies(equals('mode', 'disabled'), not(has('selectedIndex')))
)