DEV Community

Murtaza Nathani
Murtaza Nathani

Posted on • Updated on

JavaScript's unsafe optional chaining is crazy |:

Optional chaining:

Optional chaining has made life of javaScript programmer easy by handling the checks using the syntax ?.

However, here we are NOT to discuss how awesome it is, rather solving a issue how of to safely use it.


no-unsafe-optional-chaining

no-unsafe-optional-chaining is an amazing eslint rule, which help us identify what are we doing wrong with optional chaining and disallows use of optional chaining in contexts where the undefined value is not allowed.

I have one case where I need to perform a sort operation on id which could be in string type which make sense to throw error because it could result in NaN, if order is not a number as follows:


The issue



  const sortComparer = (a, b) => (+a?.order) - (+b?.order)


Enter fullscreen mode Exit fullscreen mode

My solution

However, if i do handle no-unsafe-optional-chaining as follow it still throws error and does not work:



  const sortComparer = (a, b) => (+a.order || 0) - (+b.order || 0),


Enter fullscreen mode Exit fullscreen mode

The way it worked

The only way to make it work is like this:



  const sortComparer = (a, b) => (a?.order ? +a.order : 0) - (b?.order ? +b.order : 0),


Enter fullscreen mode Exit fullscreen mode

Question ? :S

Does anyone know how to fix this in a better way to avoid this issue ?

Regards.

Top comments (11)

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited
 const sortComparer = (a, b) => ~~a?.order - ~~b?.order
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mnathani profile image
Murtaza Nathani

Umm.. this is interesting.

Would you like to share what ~~ does in the solution above and how does it fix the unsafe optional chaining ?

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

~ is a bitwise NOT operator - flipping all the bits in a number. Flipping them twice gets you back to the original number. Using it with undefined (what you'll get from the optional chain if order is missing) or any falsy value - is the same as using it with 0

I am making the presumption here that order will be an integer. The solution I suggest will also remove the decimal part from any order value

Thread Thread
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Presumably you are using optional chaining here as you are expecting a or b to possibly be undefined or null? If this is not the case, you don't even need optional chaining and could simply use:

 const sortComparer = (a, b) => ~~a.order - ~~b.order
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
mnathani profile image
Murtaza Nathani

Hey Jon, yes I am assuming the values to null or undefined, and that's the reason why I am using optional changing..

However, using your approach wouldn't ~~undefinded break the code ? 🤔

Thread Thread
 
jonrandy profile image
Jon Randy 🎖️

As I said, ~~undefined gives 0

Thread Thread
 
mnathani profile image
Murtaza Nathani

umm, interesting way.. never used it though, however not sure if this is the best practise or not..

Thread Thread
 
jonrandy profile image
Jon Randy 🎖️

Best practises should always be challenged and questioned

Thread Thread
 
mnathani profile image
Murtaza Nathani

Agreed, there's always more then one to do the stuff, whatever works best !

Collapse
 
mnathani profile image
Murtaza Nathani

For someone interested for the answers,

One of the solution I got from stackOverflow was:

  const sortComparer = (a, b) => +(a?.order || 0) - +(b?.order || 0);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ayoubmanie profile image
ayoubmanie • Edited
const sortComparer = (a, b) => ((Number(a?.order) || 0) - (Number(b?.order) || 0))
Enter fullscreen mode Exit fullscreen mode