The exclamation mark !
is named the non-null assertion operator in TypeScript. We will probably be utilizing these phrases interchangeably on this article. However what does this operator do?
On this article, we’ll check out:
What’s the TypeScript exclamation mark?
The non-null assertion operator tells the TypeScript compiler {that a} worth typed as optionally available can’t be null
or undefined
. For instance, if we outline a variable as probably a string or undefined, the !
operator tells the compiler to disregard the opportunity of it being undefined.
What the exclamation mark does in TypeScript
Let’s say a variable is outlined as probably null or undefined, like so:
let x: string | undefined
Or, let’s say a perform is outlined to just accept an optionally available argument, like so:
perform printString (str ?: string) { … }
In these circumstances, if we attempt to reference that variable as a particular sort, then the TypeScript compiler would give us an error message, similar to the next:
Object is probably 'undefined'. ts(2532)
We are able to use the non-null assertion operator to inform the compiler explicitly that this variable has a price and isn’t null
or undefined
. Let’s assessment a number of examples to raised perceive the exclamation mark in TypeScript.
Instance 1: Utilizing a variable of sort string | null
for a perform that accepts string
Let’s say we outlined a variable phrase
with the sort as string | null
. This implies all through our code, phrase
can both maintain a string
worth or a null
worth.
If we try to make use of a perform solely out there to string
varieties on phrase
, TypeScript will reject it as a result of there’s a risk in our code that phrase
holds a null
worth sort:
let phrase : string | null = null const num = 1 if (num) { phrase = "Hi there World!" } console.log(phrase.toLowerCase()) // Error: Object is probably 'null'.ts(2531)
Utilizing the !
non-null assertion operator, we will inform TypeScript we’re sure phrase
won’t ever be null
(or undefined
), so it may possibly confidently apply string capabilities to it:
let phrase : string | null = null const num = 1 if (num) { phrase = "Hi there World!" } console.log(phrase!.toLowerCase())
With this small addition, the compiler not believes there’s a risk that phrase
is null.
Instance 2: Assigning the worth of an optionally available argument to a variable inside a perform
In one other instance, let’s say we created a perform printName
that accepts an optionally available argument personName
.
Be aware that defining a perform argument as optionally available utilizing ?:
is identical as defining sort as probably undefined. For instance, arg?: string
is identical as arg: string | undefined
.
If we attempt to reassign that optionally available argument personName
to a different variable of sort string
, the next would happen:
perform printName(personName?: string) { const fullName: string = personName /** * Error: Sort 'string | undefined' will not be assignable to sort 'string'. * Sort 'undefined' will not be assignable to sort 'string'. */ console.log(`The identify is ${fullName}`) }
We are able to repair the TypeScript errors thrown in our snippet above utilizing the !
operator:
perform printName(personName?: string) { const fullName: string = personName! console.log(`The identify is ${fullName}`) }
Now, the compiler understands that personName can’t be null or undefined, making it assignable to sort string
.
Instance 3: Printing the attribute of an optionally available object argument inside a perform
In our closing instance, we’ll outline a kind Individual
and a perform printName
that accepts an optionally available argument of sort Individual
. Let’s see what occurs if we attempt to use printName
to print the identify attribute of Individual
:
interface Individual { identify: string age: quantity } perform printName(individual?: Individual) { console.log(`The identify is ${individual.identify}`) // Error: Object is probably 'undefined'. ts(2532) }
Let’s repair this TypeScript error utilizing our !
operator:
interface Individual { identify: string age: quantity } perform printName(individual?: Individual) { console.log(`The identify is ${individual!.identify}`) }
Be aware that TypeScript has an alternate for referencing attributes and capabilities on objects that is perhaps null or undefined known as the optionally available chaining operator ?.
. For instance, individual?.identify
or phrase?.toString()
will return undefined
if the variable will not be outlined or null.
Nonetheless, the optionally available chaining operator ?.
can not resolve the TypeScript errors in our second instance, by which we tried to assign the worth of a variable sort string | undefined
to a variable sort string
. Be taught extra about optionally available chaining within the final part of this text.
Fashionable use circumstances for the TypeScript exclamation mark
As we’ve seen in our examples, the !
operator could be very helpful when we wish TypeScript to deal with our variable as a strong sort. This prevents us from having to deal with any null or undefined circumstances after we are sure there isn’t a such case.
Now that now we have seen some examples to achieve a greater understanding of the TypeScript exclamation mark, let’s take a look at some widespread use circumstances for this operator.
Performing lookups on an array
Let’s think about now we have an array of objects and we need to choose an object with a selected attribute worth, like so:
interface Individual { identify: string age: quantity intercourse: string } const individuals: Individual[] = [ { name: 'Gran', age: 70, sex: 'female' }, { name: 'Papa', age: 72, sex: 'male' }, { name: 'Mom', age: 35, sex: 'female' }, { name: 'Dad', age: 38, sex: 'male' } ] const femalePerson = individuals.discover(p => p.intercourse === 'feminine')
In our snippet above, TypeScript will outline the kind of femalePerson
as Individual | undefined
as a result of it’s attainable that individuals.discover
yields no outcome — in different phrases, that it will likely be undefined.
Nonetheless, if femalePerson
has the sort Individual | undefined
, we won’t be able to go it as an argument to a perform anticipating sort Individual
.
After we are performing lookups on these arrays, we are sometimes assured that they’ve outlined values, and we subsequently don’t consider any undefined circumstances exist. Our !
operator can save us from extra — or pointless — null or undefined case dealing with.
Add the non-null assertion operator, like so:
const femalePerson = individuals.discover(p => p.intercourse === 'feminine')!
This is able to make femalePerson
have the sort Individual
.
React refs and occasion dealing with
React refs are used to entry rendered HTML DOM nodes or React parts. Refs are created utilizing React.createRef<HTMLDivElement>()
after which hooked up to the factor utilizing the ref
attribute.
To make use of React refs, we entry the present attribute, ref.present
. Till the factor is rendered, ref.present
may very well be null
, so it has the next sort:
HTMLDivElement | null
To connect an occasion to ref.present
, we’d first must deal with attainable null
values. Right here is an instance:
import React from 'react' const ToggleDisplay = () => { const displayRef = React.createRef<HTMLDivElement>() const toggleDisplay = () => { if (displayRef.present) { displayRef.present.toggleAttribute('hidden') } } return ( <div> <div class="display-panel" ref="displayRef"> <p> some content material </p> </div> <button onClick={toggleDisplay}>Toggle Content material</button> <div> ) }
Within the snippet above, we needed to deal with a kind test of displayRef.present
utilizing an if
assertion earlier than calling the toggleAttribute
perform.
Generally, we’re certain that if the button onClick
occasion is triggered, then our parts are already rendered. Subsequently, there isn’t a want for a test. This pointless test may be eradicated utilizing the !
operator, like so:
const displayRef = React.createRef<HTMLDivElement>() const toggleDisplay = () => displayRef.present!.toggleAttribute('hidden') return ( <div> ...
The draw back of utilizing the exclamation mark in TypeScript
The !
operator doesn’t change the runtime conduct of your code. If the worth you’ve got asserted will not be null
or undefined
seems to really be null
or undefined
, an error will happen and disrupt the execution of your code.
Bear in mind, the distinction between TypeScript and JavaScript is the assertion of varieties. In JavaScript we don’t want or use the !
operator as a result of there isn’t a sort strictness.
A JavaScript variable may be instantiated with string
and adjusted to object
, null
, or quantity
in the course of the execution of the code. This leaves it as much as the developer to deal with the totally different circumstances.
Utilizing the !
operator takes away TypeScript’s “superpower” of stopping runtime sort errors. Subsequently, it’s not one of the best apply to make use of the !
operator.
Options to utilizing the TypeScript exclamation mark
You could possibly use optionally available chaining or sort predicates as alternate options to non-null assertions.
Optionally available chaining is a TypeScript shorthand that permits us simply deal with the circumstances the place the variable is outlined or not. When the variable will not be outlined or null, the referenced worth defaults to worth undefined
. Right here’s an instance of optionally available chaining:
interface Individual { identify: string age: quantity intercourse: string } perform printName(individual?: Individual): void { console.log('The identify of this individual is', individual?.identify) }
In our instance above, if individual
is undefined, our print output can be as follows:
'The identify of this individual is undefined'
Utilizing sort predicates in TypeScript is completed by defining a perform that performs a boolean take a look at and returns a kind predicate within the kind arg is Sort
. Right here is an instance:
interface Individual { identify: string age: quantity intercourse: string } perform validatePerson(individual?: Individual) individual is Individual { return !!individual }
Utilizing this kind predicate, we will first validate the thing earlier than performing any additional operations, like so:
perform printName(individual?: Individual) { if (!validatePerson(individual)) { console.log('Individual is invalid') return } console.log(`The identify is ${individual.identify}`) }
Conclusion
TypeScript’s energy over JavaScript is the sort security it gives our code. Nonetheless, we might generally need to disable TypeScript’s strict sort checks — for instance, for the sake of flexibility or backward compatibility. In such circumstances, we will use the non-null assertion operator.
Although a helpful function, I encourage you to discover safer sort assertion strategies as an alternative. You may go a step additional to stop use of this operation in your mission and along with your crew by including the typescript-eslint
package deal to your mission and making use of the no-non-null-assertion
lint rule.
Writing a whole lot of TypeScript? Watch the recording of our current TypeScript meetup to find out about writing extra readable code.
TypeScript brings sort security to JavaScript. There is usually a stress between sort security and readable code. Watch the recording for a deep dive on some new options of TypeScript 4.4.