Consultant, Full Stack Dev, Game addict. Tech Lead @ MOBIKO. Loving Nodejs, Typescript and Vue. Interested in Clean Code, agile methods and Software Engineering
In my opinion the main problem in this particular case is not the tenary operator - it's the ugly code that results from the violation of the DRY principle at the "error throwing".
Let's break this down a bit:
You have several "I validate a field"-things going on.
each of them will reject the "overall"-Promise, when the validation is not valid.
if every field validation is successfull, the Promise is resolved.
Why don't you just tell your program exactly this idea?
"I validate a field" becomes a function, that rejects a Promise on error, or resolves it if everything is fine:
// async can be Replaced with new Promise(bla)validateField=async(condition,message)=>{if(!condition)thrownewError(message);}
Now we can set a condition and get a resolved / rejected Promise back - we just need to execute all of them (with Promise.all) and use the overall success as indicator, that all validation was successful:
constvalidateForm=({field1,field2,field3})=>Promise.all([validateField(!!field1,'Missing field1'),validateField(Array.isArray(field2),'field 2 is not an Array'),validateField(!isValidType(field3),'field3 is invalid')]);
I think that this increases readability by several levels and tells us on the first glance, what it's doing. You might even add other fancy stuff in the "validateField"-Function, which applies to all validations, or you can use the "validateField"-part without calling the validateForm-Function.
I think if I found your piece of code, I would've refactored it like that and I can imagine, other places where "multiple" tenarys would be needed can be refactored like that as well.
validateField seems reasonable, but I am not sure why it is asynchronous. All of the field information seems to be available as-is, so it looks as though validateField and validateInput could be simplified:
constmain=()=>{constobj={field2:[1,2,3],field3:'joe'}result=validateInput(obj)result.then(success=>console.log('validation was successful')).catch(error=>console.log(`${error}`))}constvalidateInput=({field1,field2,field3})=>{try{validateField(exists(field1),'Missing field1')validateField(Array.isArray(field2),'field 2 is not an Array')validateField(isValidType(field3),'field3 is invalid')returnPromise.resolve()}catch(error){returnPromise.reject(error)}}constvalidateField=(condition,message)=>{if(!condition)thrownewError(message)}//implemented as a stubconstisValidType=field=>true//not sure if there needs to be a distinction between boolean//fields that are set to false, fields that are set to null or empty string, //and fields that simply don't exist in the objectconstexists=field=>field!=undefinedmain()//Error: Missing field1
Also, I'm not sure why there are negations in !!field1 and !isValidType(field3).
Consultant, Full Stack Dev, Game addict. Tech Lead @ MOBIKO. Loving Nodejs, Typescript and Vue. Interested in Clean Code, agile methods and Software Engineering
I just made it async, because I was too lazy to write new Promise bla (async always returns a Promise). Also I used Promise.all because I guessed that Avalander had some fancy async validation stuff going on.
!!field1 casts a value to a boolean (a bit hacky, I know 😉 Just wanted to point out, that someone should provide a boolean value).
!isValidType is taken from the original post - of course non-negated conditions should be preferred.
Yeah, let's not forget that the code I posted is a simplification of the real problem, but we can ignore the asynchronous part, I just wanted to discuss the chained conditional operators.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
In my opinion the main problem in this particular case is not the tenary operator - it's the ugly code that results from the violation of the DRY principle at the "error throwing".
Let's break this down a bit:
Why don't you just tell your program exactly this idea?
"I validate a field" becomes a function, that rejects a Promise on error, or resolves it if everything is fine:
Now we can set a condition and get a resolved / rejected Promise back - we just need to execute all of them (with Promise.all) and use the overall success as indicator, that all validation was successful:
I think that this increases readability by several levels and tells us on the first glance, what it's doing. You might even add other fancy stuff in the "validateField"-Function, which applies to all validations, or you can use the "validateField"-part without calling the validateForm-Function.
I think if I found your piece of code, I would've refactored it like that and I can imagine, other places where "multiple" tenarys would be needed can be refactored like that as well.
What do you think about this attempt?
Using
Promise.all
is a very interesting approach, I like it.validateField
seems reasonable, but I am not sure why it is asynchronous. All of the field information seems to be available as-is, so it looks as thoughvalidateField
andvalidateInput
could be simplified:Also, I'm not sure why there are negations in
!!field1
and!isValidType(field3)
.I just made it async, because I was too lazy to write new Promise bla (async always returns a Promise). Also I used Promise.all because I guessed that Avalander had some fancy async validation stuff going on.
!!field1 casts a value to a boolean (a bit hacky, I know 😉 Just wanted to point out, that someone should provide a boolean value).
!isValidType is taken from the original post - of course non-negated conditions should be preferred.
Yeah, let's not forget that the code I posted is a simplification of the real problem, but we can ignore the asynchronous part, I just wanted to discuss the chained conditional operators.