In TypeScript, what does the exclamation mark (!) operator do when dereferencing a member?
I encountered this operator while examining the source code for a TSLint rule. For example:
if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
return;
}
Initially, I tried compiling this with TypeScript 1.5.3, and it resulted in an error pointing to the exclamation mark:
$ tsc --noImplicitAny memberAccessRule.ts
noPublicModifierRule.ts(57,24): error TS1005: ‘)’ expected.
However, after upgrading to TypeScript 2.1.6, the code compiled successfully, but the exclamation mark was ignored in the resulting JavaScript:
if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
return;
}
What is the purpose of the TypeScript exclamation mark (!) operator , and how does it function?
The typescript exclamation mark (!
) operator is called the non-null assertion operator. It tells the TypeScript compiler that a value is guaranteed to not be null or undefined at that point, even if the type checker can’t infer that on its own. This comes in handy when TypeScript can’t determine the nullability of a variable, but the developer knows it’s safe.
Here’s a snippet from TypeScript’s release notes:
The !
operator is used as a postfix to assert that the operand is neither null nor undefined. It helps in cases where the type checker doesn’t have enough information. For example, x!
asserts that x
is not null or undefined. Importantly, the !
operator doesn’t affect the generated JavaScript—it’s purely for TypeScript’s type-checking and gets removed during transpilation.
Though the term “assertion” might seem like a runtime check, it’s just a developer’s way of informing the compiler without any runtime impact.
To add a bit more detail, the typescript exclamation mark (!
) operator essentially acts like a shorthand for telling TypeScript, ‘Trust me, this variable won’t be null or undefined here.’ It’s particularly useful in cases where TypeScript’s type inference is uncertain, but you, as a developer, are confident about the state of the variable.
For example, if you’ve got a variable that might initially be null
, but after certain logic (like a condition or initialization), you know it’s safe, you can use !
to bypass TypeScript’s strict null checks.
Let’s say you have this situation:
let userInput: string | null = getInput();
console.log(userInput!.toUpperCase());
Even though userInput
might be null
when it’s declared, you’re telling TypeScript by adding !
that it won’t be null at the point of using it, so TypeScript doesn’t throw errors.
Keep in mind that this is purely a compile-time assertion—it doesn’t generate any extra JavaScript code and won’t prevent runtime null errors. So, use it carefully!
Absolutely, Babita’s example is spot on! Just to build further, the typescript exclamation mark (!
) operator is extremely helpful when dealing with optional chaining or nullable types, especially in larger TypeScript projects where variables might go through several transformations or conditions.
One important thing to note: while the !
operator can silence TypeScript’s complaints about potential null
or undefined
values, it doesn’t add any runtime checks. So, if your variable actually is null at runtime, you’ll still face runtime errors.
Let me expand on the example with a more common scenario:
let referenceA: string | null = null;
const n = 1;
if (n) {
referenceA = "Hello My World!";
}
console.log(referenceA.toLowerCase()); // Error: Object is possibly 'null'.ts(2531)
Here, TypeScript complains because referenceA
is potentially null. But you know that once n
is truthy, referenceA
will definitely be a string. So, by using the !
operator, you can reassure TypeScript:
console.log(referenceA!.toLowerCase()); // No error now
By adding !
, you’re asserting that referenceA
won’t be null at this point in the code.
However, a good practice is to use it sparingly and only when you’re absolutely certain. Sometimes, using TypeScript’s optional chaining (?.
) or explicit null checks can provide safer alternatives.