0

I wrote code like this:

query = (type) ? (parent) ? { parent: parent } : { type: type } : {}

I didn't know that nested ternary should be avoided. But what would be a short way to write that correctly?

This seems not to be very short - and I don't know if that is correct:

if (type && parent)
    query = { parent: parent };
else if (type && !parent)
    query = { type: type };
else
    query = {};
user3142695
  • 15,844
  • 47
  • 176
  • 332

3 Answers3

4

Nested ternary operators are often not very readable. Your example is relatively easy. However, when nesting the operators differently, you have to know the execution order to properly understand it. For example (borrowed from here):

a == b ? a : b ? c : d 

Is it obvious to you how this will be executed? Is it

(a == b ? a : b) ? c : d 

or

a == b ? a : (b ? c : d) 

? In JavaScript, the ternary operator is right associative which means it evaluates to the latter. In some programming languages, the ternary operator is not right but instead left associative. This shows that nesting ternary operators can be confusing and, thus, should either be avoided or explicitly done by adding parentheses.


If you want a oneliner to your specific question, you can use this:

var query = (type && parent && {parent:parent}) || (type && {type:type}) || {};

However, the following is much more readable in my opinion:

var query = {};
if (type) {
    query = parent ? { parent: parent } : { type: type };
}
str
  • 42,689
  • 17
  • 109
  • 127
0

Two expressions for First conditional operator (?) will be the result of (parent) ? { parent: parent } : { type: type } and last expression {}.

The way it works is

var a  = 1, b = 2;
console.log( a == 1 ? b == 2 ? 3 : 2 : 1 );//outputs 3 
console.log( a == 2 ? b == 2 ? 3 : 2 : 1 );//outputs 1 
console.log( a == 1 ? b == 1 ? 3 : 2 : 1 );//outputs 2 

So, the a==1 is evaluated first and then it goes to second one b==2 .

So, you need to do

if ( type )
{
   if (parent)
   {
     query = { parent: parent };
   }
   else
   {
     query = { type: type };
   }
}
else
{
     query = {};
}
gurvinder372
  • 66,980
  • 10
  • 72
  • 94
  • That oneliner has a different behaviour. It sets the `type` regardless of `parent` and sets the `parent` even without `type`. – str Jul 16 '16 at 10:28
  • @str Not sure if I get this, but looking at the OP's code I don't think type and parent are in context of each other so it will set `type` regardless of `parent` and sets the `parent` even without `type`. – gurvinder372 Jul 16 '16 at 10:30
  • Yes they are, even your long form shows it. Set `parent` if `type && parent`, set `type` if `type && !parent`, otherwise set `{}`. – str Jul 16 '16 at 10:39
  • @str Oh you mean to say that order of chaining is different from my last one-liner? – gurvinder372 Jul 16 '16 at 10:45
  • It is not just the order. See the oneliner from my answer. – str Jul 16 '16 at 10:58
  • @str Got it now. Dropping it altogether since it is not getting any easier if OP already had a concern with its existing one. – gurvinder372 Jul 16 '16 at 11:04
0

How about this:

var query = {};

if (type){
    if(parent){
        query = {parent: parent};
    }else{
        query = {type: type};
    }
}
Rahul Arora
  • 4,503
  • 1
  • 16
  • 24