DEV Community

loading...
Cover image for Safe Navigation Operator? Bang! Bang Bang!!

Safe Navigation Operator? Bang! Bang Bang!!

pssingh21
Hello World.
・3 min read

Safe Navigation Operator

Safe navigation operator or optional chaining is now available in JavaScript and TypeScript >= v3.7🎉.

It provides easy access to deeply nested values, so checking for nullish (undefined or null) values is simplified. We avoid hitting the classic JavaScript error:

Uncaught TypeError: Cannot read property 'foo' of undefined.
Enter fullscreen mode Exit fullscreen mode

A common workaround would be to short-circuit using the && operator. However, this would quickly unwind to long repetitive chains if we need to check for a deeply nested object.

const foo = a && a.b && a.b.c && a.b.c.d && a.b.c.d[0];
Enter fullscreen mode Exit fullscreen mode

A lodash solution might look like

const foo = _.has(a, 'b.c.d[0]');
Enter fullscreen mode Exit fullscreen mode

The safe navigation operator approach looks like

const foo = a?.b?.c?.d[0];
Enter fullscreen mode Exit fullscreen mode

Returns undefined if the value does not exist.

This approach is recommended since it has now been added to the language and is browser supported. //! Except Internet Explorer

This also works with function calls, array indexes and chaining dynamic expressions.

const foo = a?.b //accessing object property
const foo = a?.[expr] //accessing through dynamic expression
const foo = arr?.[index] //accessing array index
const foo = bar?.(args) //conditional function call
Enter fullscreen mode Exit fullscreen mode

Warning: This operator is not valid on the left-hand-side of an assignment operator.

const a?.b = foo; //Invalid
Enter fullscreen mode Exit fullscreen mode

Note: ?. acts differently than && operator, since the && operator acts on falsy values(including 0, NaN, "", false), but ?. acts on nullish values (null and undefined).

TypeScript Bang! (non-null assertion operator)

Warning: !. is not the same as ?. . The ! postfix expression is valid in TypeScript >= v2.0. The a! operator produces a value a with null and undefined excluded. Meaning, this will explicitly tell the compiler that you are sure the type of value is not null or undefined. The compiler will thus not check if the value is null or undefined in compile time.

This could come in handy while working with maps.

const value = map.has('key') && map.get('key')!;
Enter fullscreen mode Exit fullscreen mode

In this case, the compiler does not keep track that map.has() has been evaluated while evaluating map.get(). So the compiler can't determine if the map returns a safe value.

This can also be used in terms of calling a possibly undefined function and array indexes.

func!(args);
arr![0];
Enter fullscreen mode Exit fullscreen mode

For example it could be used when using React refs. When using refs, the current value may be null if the element is unmounted.

JavaScript Bang! (prefix operator)

In JavaScript every value is assocaiated as either a truthy value or a falsy value. So, a bang(!) as a prefix on a value acts as a logical "not" operator on that value.

!true; //returns false
!false; //returns true

!1 //returns false
!5 //returns false

!0 //returns true
!NaN //returns true
!null //returns true
!undefined //returns true

![] //returns false (points to a reference)

const foo = "bar";
!foo //returns false

const baz = null;
!baz //returns true
Enter fullscreen mode Exit fullscreen mode

JavaScript Bang Bang!!

Since a bang (!) acts as a logical "not" on a value, a double bang negates the result of the logical "not" operation. So, a double bang will first change the value to a boolean opposite, and return the opposite of that. In other words, it converts any value into a boolean type.

Note: The ! operator operates on truthy and falsy values and is not limited to nullish values. So, !'' should resolve to true.

!!true //returns true
!!false //returns false

!!null //returns false
!!undefined //returns false
!!NaN //returns false

!!34 //returns true
!!0 //returns false

!!'foo' //returns true
!!'' //returns false

!!['foo'] //returns true
!![] //returns true (points to a reference)

!!{foo: 'bar'} //returns true
!!{} //returns true (points to a reference)
Enter fullscreen mode Exit fullscreen mode

Happy Hacking!

Discussion (4)

Collapse
kinakuta profile image
James Donaldson

The safe navigation operator also pairs well with the nullish coalescing operator for providing defaults like what you get with lodash get:

const foo = get(a, 'b', {});

can be expressed as

const foo = a?.b ?? {};

And the nullish coalescing operator protects from logical bugs where you want 0 or false to be considered valid values.

Collapse
myleftshoe profile image
myleftshoe

Bang! Bang! Bang! - sounds pretty unsafe to me

Collapse
pssingh21 profile image
pssingh21 Author

Bang! as a postfix operator in typescript is unsafe I agree. But JavaScript Bangs aren't unsafe . They are used just to convert any value to a Boolean equivalent.

Collapse
myleftshoe profile image
myleftshoe

No sorry, it was a joke - bang! bang! bang! sounds like a triple gunshot which is obviously unsafe.