Are you familiar with expressions like these:
a !== undefined && a !== null ? a : b
if (a.x === undefined || a.x === null) { a.x = b }
{ foo: foo, bar: bar }
a ? a.b : undefined
function getX(o) { return o.x }
What do they all have in common? They are highly verbose, and all have a nice shorthand alternatives. Let's see how we can improve each one of these:
Nullish coalescing operator ??
This operator checks the value of the left hand-side operand - if it's null or undefined, it returns the right hand-side operand. Otherwise it returns the left hand-side, without evaluating the right hand-side.
This allows simplifying the following expression:
a !== undefined && a !== null ? a : b
To this:
a ?? b
Unlike ||
operator that checks for any falsy value, this operator only checks for nullish values - meaning null
or undefined
. Therefore it is safer to use in cases that a
is a boolean which can be false
or a number which can be 0
, and then a || b
will return the value of b
Nullish coalescing assignment ??=
This operator only evaluates the right operand and assigns to the left if the left operand is null or undefined.
So we can simplify this expression:
if (a.x === undefined || a.x === null) {
a.x = b
}
to this:
a.x ??= b
JSON shorthand syntax
The shorthand syntax was introduced with ES6 and is already pretty common.
Use it to shorten this:
const name = 'john doe'
const age = 32
const talk = text => void console.log(text)
const person = {
name: name,
age: age,
talk: talk
}
to that:
const name = 'john doe'
const age = 32
const talk = text => void console.log(text)
const person = {
name,
age,
talk
}
Optional chaining ?.
This operator accesses an object's property just like .
does. However, unlike .
, if the object is null or undefined, the expression will return undefined
instead of throwing an error.
This allows replacing this code:
a ? a.b : undefined
with that:
a?.b
This operator is pretty strong, and can be used in various ways:
- Chaining:
a?.b?.c?.d
- Call interface method:
someInterface.customMethod?.()
Note that in this case, ifcustomMethod
exists, but it is not a function, you'd still get an exceptionsomeInterface.customMethod is not a function
- Access dynamic property with bracket notation:
x?.[propname]
- Access array items:
array?.[50]
- even if array is nullish, you'd getundefined
instead of an exception
Arrow functions
There's a lot to say about arrow functions, but in the context of this post I want to focus on a specific use - 1 liner methods that calculate something or access some property. They have 2 attributes that help with code shortening:
- Arrow functions that do not have a block body wrapped with curly brackets
{/*...*/}
have an implicitreturn
. - in a single-param arrow function you do not have to put the argument in parentheses Meaning, you can change this:
function getX(o) {
return o.x
}
with this
const getX = o => o.x
This is super useful, for example, for mapping functions.
Note that there are some caveats though:
- Arrow functions do not have
this
- Arrow functions do not have
arguments
. You can use spread operator instead. E.g(...args) => args[0]
- Arrow functions cannot call
super
or be used as constructors
Top comments (0)