Last updated: Feb 29, 2024
Reading timeยท3 min
The exclamation mark (non-null assertion) operator removes null
and
undefined
from the type of an expression.
It is used when we know that a variable that TypeScript thinks could be null
or undefined
actually isn't.
type Employee = { id: number; name: string; }; function getEmployeeName(emp?: Employee) { return emp!.name; // ๐๏ธ use non-null assertion } // ๐๏ธ "Bobby Hadz" console.log(getEmployeeName({ id: 1, name: 'Bobby Hadz' }));
The
exclamation mark (non-null assertion)
operator removes null
and undefined
from a type.
The emp
parameter in the function is marked as
optional, which means that it
can either be of type Employee
or be undefined
.
null
and undefined
from the type of the variable.Had we not used the non-null assertion operator, we would have gotten an error
when trying to access the name
property.
type Employee = { id: number; name: string; }; function getEmployeeName(emp?: Employee) { // โ๏ธ Error: Object is possibly 'undefined'.ts(2532) return emp.name; } // ๐๏ธ "Frank" console.log(getEmployeeName({ id: 1, name: 'Frank' }));
The emp
parameter is possibly undefined
, so we cannot safely access a
property on it, as it could potentially cause a runtime error.
It's very important to note that the exclamation mark operator is simply a type assertion.
In other words, it doesn't add any type-safety to your program.
It doesn't
check if the specified variable is not null
and not undefined
.
null
and undefined
from the type of the variable.When we use the non-null assertion operator, we effectively tell TypeScript that
this variable is never going to be null
or undefined
and not to worry about
it.
The operation myVar!
produces a value of the type of myVar
with null
and
undefined
removed.
The code sample that used the non-null assertion operator is very similar to this code sample that uses a simple type assertion.
type Employee = { id: number; name: string; }; function getEmployeeName(emp?: Employee) { return (emp as Employee).name; // ๐๏ธ type assertion } // ๐๏ธ "Bobby Hadz" console.log(getEmployeeName({ id: 1, name: 'Bobby Hadz' }));
We tell TypeScript that the emp
variable is going to be of type Employee
and
not to worry about it.
null
and undefined
Sometimes, we really can't be sure that the specific variable is not going to be
null
or undefined
, but need to access a property on it.
In this case, it's much safer to use the optional chaining (?.) operator.
type Employee = { id: number; name: string; }; function getEmployeeName(emp?: Employee) { return emp?.name; // ๐๏ธ use optional chaining } // ๐๏ธ "Bobby Hadz" console.log(getEmployeeName({ id: 1, name: 'Bobby Hadz' }));
The optional chaining (?.) operator
short-circuits and returns undefined
if the value to the left is nullish
(null
or undefined
).
This is why TypeScript allows us to use it to access the name
property on the
emp
variable that could be undefined
.
null
or undefined
, the optional chaining operator short-circuits without throwing any errors.if
statement as a type guardAlternatively, you could use an if
statement that serves as a
type guard.
type Employee = { id: number; name: string; }; function getEmployeeName(emp?: Employee) { if (emp) { // ๐๏ธ emp is type Employee here return emp.name; } // ๐๏ธ emp is type undefined here return 'Bobby Hadz'; } // ๐๏ธ "Bobby Hadz" console.log(getEmployeeName({ id: 1, name: 'Bobby Hadz' }));
Our if
statement serves as a type guard because TypeScript knows that if the
condition is met, the emp
variable is of type Employee
.
Otherwise, the variable has a type of undefined
because that's the only other
possible type.