Mike Chamberlain
Mike Chamberlain

Reputation: 42510

In TypeScript, what is the ! (exclamation mark / bang) operator when dereferencing a member?

When looking at the source code for a tslint rule, I came across the following statement:

if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

Notice the ! operator after node.parent. Interesting!

I first tried compiling the file locally with my currently installed version of TS (1.5.3). The resulting error pointed to the exact location of the bang:

$ tsc --noImplicitAny memberAccessRule.ts 
noPublicModifierRule.ts(57,24): error TS1005: ')' expected.

Next, I upgraded to the latest TS (2.1.6), which compiled it without issue. So it seems to be a feature of TS 2.x. But, the transpilation ignored the bang completely, resulting in the following JS:

if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

My Google fu has thus far failed me.

What is TS's exclamation mark operator, and how does it work?

Upvotes: 1421

Views: 620431

Answers (7)

Daham Akl
Daham Akl

Reputation: 628

TS's exclamation mark operator: It's used to set the not-nullable references. It tells the typescript compiler that the variable can't be Null or undefined. Please check the following example.

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)

To avoid that error we need to tell the compiler that the variable can't be Null using the "!" operator, which's called non-null assertion operator.

    let referenceA: string | null = null
    const n = 1
    if (n) {
        referenceA= "Hello My World!"    
    }
    console.log(referenceA!.toLowerCase())

Upvotes: 6

MANAV GUPTA
MANAV GUPTA

Reputation: 126

Non-Nullable TypeScript performs strict null checks to help catch potential null or undefined errors. When you try to access a member (property or method) on a variable that could be null or undefined, TypeScript raises a compilation error.

let myElement: HTMLElement | null = document.getElementById('myElement');

// Without non-null assertion operator
// Compiler error: Object is possibly 'null'.
myElement.innerHTML = 'Hello, world!';

// With non-null assertion operator
myElement!.innerHTML = 'Hello, world!';

Upvotes: 7

Louis
Louis

Reputation: 151491

That's the non-null assertion operator. It is a way to tell the compiler "this expression cannot be null or undefined here, so don't complain about the possibility of it being null or undefined." Sometimes the type checker is unable to make that determination itself.

It is explained in the TypeScript release notes:

A new ! post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. Specifically, the operation x! produces a value of the type of x with null and undefined excluded. Similar to type assertions of the forms <T>x and x as T, the ! non-null assertion operator is simply removed in the emitted JavaScript code.

I find the use of the term "assert" a bit misleading in that explanation. It is "assert" in the sense that the developer is asserting it, not in the sense that a test is going to be performed. The last line indeed indicates that it results in no JavaScript code being emitted.

Upvotes: 1965

hfutsora
hfutsora

Reputation: 161

My understanding is the ! operator do the same thing like NonNullable.

let ns: string | null = ''
//  ^? let ns: string | null
let s1 = ns!
//  ^? let s1: string
let s2 = ns as NonNullable<typeof ns>
//  ^? let s2: string

Upvotes: 9

Willem van der Veen
Willem van der Veen

Reputation: 36650

Non-null assertion operator

With the non-null assertion operator we can tell the compiler explicitly that an expression has value other than null or undefined. This is can be useful when the compiler cannot infer the type with certainty but we have more information than the compiler.

Example

TS code

function simpleExample(nullableArg: number | undefined | null) {
   const normal: number = nullableArg; 
    //   Compile err: 
    //   Type 'number | null | undefined' is not assignable to type 'number'.
    //   Type 'undefined' is not assignable to type 'number'.(2322)

   const operatorApplied: number = nullableArg!; 
    // compiles fine because we tell compiler that null | undefined are excluded 
}

Compiled JS code

Note that the JS does not know the concept of the Non-null assertion operator since this is a TS feature

"use strict";
function simpleExample(nullableArg) {
    const normal = nullableArg;
    const operatorApplied = nullableArg;
}

Upvotes: 97

Masih Jahangiri
Masih Jahangiri

Reputation: 10957

Short Answer

Non-null assertion operator (!) helps the compiler that I'm sure this variable is not a null or undefined variable.

let obj: { field: SampleType } | null | undefined;

... // some code

// the type of sampleVar is SampleType
let sampleVar = obj!.field; // we tell compiler we are sure obj is not null & not undefined so the type of sampleVar is SampleType

Upvotes: 47

Mike Chamberlain
Mike Chamberlain

Reputation: 42510

Louis' answer is great, but I thought I would try to sum it up succinctly:

The bang operator tells the compiler to temporarily relax the "not null" constraint that it might otherwise demand. It says to the compiler: "As the developer, I know better than you that this variable cannot be null right now".

Upvotes: 462

Related Questions