Cover image by Talles Alves on Unsplash
Internet wisdom says that nested conditional operators are evil. And I firmly believed internet wisdom until today.
Today I found myself refactoring some old Javascript code and it had one of those functions that validate that a heckload of properties exist and have the right format in an object. Then I went crazy and wrote something similar to this.
const validateInput = ({ field1, field2, field3 }) =>
(!field1
? Promise.reject('Missing field1')
: !Array.isArray(field2)
? Promise.reject('field2 is not an array')
: !isValidType(field3)
? Promise.reject('field3 is invalid')
: Promise.resolve()
)
Don't mind the thing with promises, this function is used inside a promise chain.
The thing is, it makes me cringe a bit because, you know, nested conditional operators are evil, but I actually find it readable, and I'd say it might even flow better than the chain of ifs.
I would like to read your thoughts and opinions in the topic. Are nested conditional operators inherently evil and unreadable or are they alright, they have just been used in a messy manner for too long?
I think the fact that the design of a conditional (especially ternary) is not restrictive says nothing of how it is used. I find in most cases where I desire to write less code, that using a normal if conditional is actually better even if it promotes greater nesting.
I have been developing more classic writing habits of late though, so take that with a grain of salt? I prefer conditionals with closure to support flexible scope without rewriting anything, and they clearly define line-breaks. My writing preference of your function would look something like this (I don't fully understand Promises yet):
Taking a look at your function, for example; I would write this as separate conditional checks because they are not related to one another. This is a pattern I find useful when designing other functions, often I only want to check for a single condition, not a chain of if/else conditions. In this function, you only want to return a rejection if a field fails a conditional check. Try to think of it as 'If this is true than do this', not 'if this is true do this, otherwise check for these things and do this'.
This is what the if/else would look like using normal conditionals.
As for ternary conditionals, I only ever write them inline for simple checks and I have read and agree that they should not be nested more than 1-2 levels.