Как избежать вложенных тернарных выражений в моем коде?

У меня есть такой код. Как я могу написать это чище и элегантнее, используя функциональное программирование на JavaScript? Я хочу избавиться от вложенных тернарных выражений. Любые идеи?

props => ({
            iconColor: props.isPriority ? (props.isCompleted ? variables.color.lightpurple : variables.color.purple ) : variables.color.gray3,
            iconName: props.isPriority ? 'star-full' : 'star-empty',
          }))

Это остальная часть этого кода:

ИЗМЕНИТЬ:

const enhance: React$HOC<*, InitialProps> = compose(
      withProps(props => ({
        iconColor: props.isPriority ? (props.isCompleted ? variables.color.lightpurple : variables.color.purple) : variables.color.gray3,
        iconName: props.isPriority ? 'star-full' : 'star-empty',
      }))
    )

person MountainConqueror    schedule 18.09.2017    source источник
comment
создать функцию, вызвать ее   -  person Jaromanda X    schedule 18.09.2017
comment
Очиститель?? уже достаточно чисто   -  person Jonas Wilms    schedule 18.09.2017
comment
Чистота очень субъективна.   -  person Quentin    schedule 18.09.2017
comment
@Jonasw, Да, но мой линтер недоволен: 44:16 error Do not nest ternary expressions [no-nested-ternary]   -  person MountainConqueror    schedule 18.09.2017
comment
@JaromandaX - могу ли я создать эту функцию и вызвать ее внутри оболочки withProps? Это будет работать?   -  person MountainConqueror    schedule 18.09.2017
comment
Это уже написано чище, но использует функцию стрелки (javascript.info/function-expressions-arrows #arrow-functions) (признан ECMAScript – 6). Если вы хотите вернуться к обычной функции, просто создайте несколько функций, чтобы разделить это и использовать возвращаемый результат.   -  person Hanif    schedule 18.09.2017


Ответы (4)


Да, но мой линтер недоволен: 44:16 error Do not nest ternary expressions [no-nested-ternary]

Если это ваша единственная проблема, то решение простое. Создайте свою собственную условную функцию:

const iff = (condition, then, otherwise) => condition ? then : otherwise;

props => ({
  iconColor: props.isPriority ?
    iff(props.isCompleted, variables.color.lightpurple, variables.color.purple) :
    variables.color.gray3,
  iconName: props.isPriority ? 'star-full' : 'star-empty',
})

Теперь ваш линтер не должен жаловаться. При этом вы должны отключить [no-nested-ternary] в своем линтере. Довольно глупо, что ваш линтер считает вложенные условные операторы плохими.

person Aadit M Shah    schedule 20.09.2017
comment
Это просто обман ESLint и добавление косвенности. Я согласен, что это правило следует отключить, если нет подходящих альтернатив. Не могли бы вы отредактировать ответ, включив в него более заметное решение по изменению конфигурации eslint вместо добавления функции, которая никоим образом не приносит пользы кодовой базе и просто затрудняет чтение? - person Cedomir Rackov; 09.05.2020
comment
Это не глупо, линтер не жалуется на вложенные условные операторы, жалуется на то, что вложенные тернарные операторы, как правило, плохи для ясности кода. - person Eric Van Der Dijs; 23.07.2021
comment
@ Эрик Ван Дер Дийс Это спорно. Исходя из опыта функционального программирования, я думаю, что вложенные условные операторы хороши для ясности кода, пока они не станут слишком громоздкими. Команда программистов должна решать, что считать хорошим кодом, а что плохим. Линтер не должен навязывать программисту предпочтительный стиль. - person Aadit M Shah; 26.07.2021
comment
Обратите внимание, что я никогда не говорил, что вложенные условные операторы плохи для ясности. Я говорил только о написании вложенных условных выражений с использованием тернарного оператора (т. е. условие ? 'foo' : otherConditon ? 'bar' : 'baz'), но, конечно, стиль кода полностью зависит от вашей команды. решений, я говорю только об общем стандарте. - person Eric Van Der Dijs; 28.07.2021

В этом случае вы можете рассмотреть возможность инвертирования условия, чтобы удалить «неестественное» вложение троичных элементов. Вложенность по-прежнему будет, но ее можно написать плоской — без круглых скобок — что означает, что вы можете аккуратно разложить ее по нескольким строкам:

props => ({
    iconColor:
        !props.isPriority ? variables.color.gray3
        : props.isCompleted ? variables.color.lightpurple
        : variables.color.purple,
    iconName: props.isPriority ? 'star-full' : 'star-empty',
})

Обратной стороной этого является использование отрицательного условия, которого я обычно стараюсь избегать, поскольку им немного сложнее следовать, чем положительным условиям.

Еще один вариант — сгладить условия с помощью &&:

props => ({
    iconColor:
        props.isPriority && props.isCompleted ? variables.color.lightpurple
        : props.isPriority ? variables.color.purple
        : variables.color.gray3,
    iconName: props.isPriority ? 'star-full' : 'star-empty',
})
person TheQuickBrownFox    schedule 29.09.2017

Я согласен с @JaromandaX об использовании функции. Это сохраняет ваш JSX в чистоте, а вашу логику можно использовать повторно.

Кроме того, чтобы избежать вложенного тернарного оператора, вы можете попробовать что-то вроде этого:

  • Сохраняйте массив/карту всех возможных значений
  • На основе флагов создайте двоичную строку и преобразуйте ее в число.
  • вернуть значение по указанному индексу

function withTernary(a, b){
  return a ? (b ? 'test': 'foo') : 'bar';
}

function withoutTernary(a, b){
  var result = ['bar', undefined, 'foo', 'test'];
  // or may be a map
  /*
  * map = {
  *    '00': 'bar',
  *    '10': 'foo',
  *    '11': 'test'
  * }
  */
  var index = parseInt((+a) + '' + (+b), 2);
  return result[index];
}

var testCase = [[0,0], [1, 0], [1,1]];

testCase.forEach(x => {
  console.log('With Ternary:', withTernary(...x));
  console.log('Without Ternary:', withoutTernary(...x));
})

person Rajesh    schedule 18.09.2017
comment
Примечание. Это альтернативный подход, позволяющий избежать вложенных тернарных операторов. Если вы считаете что-либо в этом ответе ненужным/необязательным/неправильным, пожалуйста, прокомментируйте вместе с вашим голосованием. Хорошего дня. - person Rajesh; 18.09.2017

Можно было бы использовать IIaFE (немедленно вызываемое выражение функции стрелки):

props => ({
        iconColor:(_=>{
           if(props.isPriority){
             if(props.isCompleted){
               return variables.color.lightpurple;
             }
             return variables.color.purple;
           }
           return variables.color.gray3;
        })(),
        iconName:(_=>{ 
           if(props.isPriority){
              return 'star-full';
           }
           return 'star-empty';
       })()
}))
person Jonas Wilms    schedule 18.09.2017
comment
Я не думаю, что нам нужна функция стрелки, так как мы не используем в ней this. Кроме того, наличие предопределенной функции всегда лучше встроенной функции, поскольку она добавляет возможность ее повторного использования. - person Rajesh; 18.09.2017
comment
IIFE не особенно функциональны. Вместо этого используйте повторно используемую функцию, например const apply = (...args) => f => f(...args). Коду становится легче следовать, и вы даже можете деструктурировать аргументы f: apply(props) (({isPriority, isCompleted}) => { switch (isPriority) {...}}). - person ; 18.09.2017