Menu

TypeScript Exclamation Mark: The Non-Null Assertion (!)

An exclamation mark after a value, like user!, is the non-null assertion operator: it removes null and undefined from the type without any runtime check. Learn what x! does, the definite assignment forms let x!: T and prop!: T, why they are risky, and safer alternatives.

This page includes runnable editors - edit, run, and see output instantly.

An exclamation mark after an expression, value!, is the non-null assertion operator. It removes null and undefined from the type, so a number | undefined can be used as a number. It is a promise to the compiler, not a check: nothing happens at runtime.

Without the !, tea.toFixed(2) is error TS18048, 'tea' is possibly 'undefined'. With it, the code compiles because you told the compiler the key exists.

What x! Does at Runtime: Nothing

The ! is erased from the output. The compiled JavaScript for prices.get("coffee")! is just prices.get("coffee"). If the assertion is wrong, the error appears later, at the first place the missing value is used:

The program prints Cannot read properties of undefined (reading 'toFixed'). The crash happens on the line after the !, and in real code it can be much further away: the undefined may be stored in an object and blow up in a different file. That distance is why ! is risky.

Definite Assignment: let x!: T

The same symbol in a declaration means something related. TypeScript tracks whether a variable is assigned before it is read, and it cannot follow an assignment made inside another function:

index.ts(9,13): error TS2454: Variable 'config' is used before being assigned.

let config!: { port: number }; is a definite assignment assertion: "this will be assigned before any read". It fixes the error, with the same catch as x!: if init() is ever skipped, the read gets undefined. Restructuring is usually better, for example const config = init(); with init returning the object.

Class Properties: prop!: T

With strictPropertyInitialization (part of strict), every class property must be initialized in its declaration or in the constructor. Otherwise you get TS2564: Property 'socket' has no initializer and is not definitely assigned in the constructor. When a property is set later by a method or a framework, prop!: T tells the compiler to accept it:

The first console.log shows the gap: the type says socket is always there, but before open() it is undefined. Calling c.socket.send at that point compiles and throws. If the property can really be missing, declare it socket?: ... and check it, or create the object in the constructor. The main place prop! is standard practice is a framework that fills a property after construction: Angular's @ViewChild(...) child!: ChildDirective (set before ngAfterViewInit runs), or ORM entity classes whose columns the library fills when it loads a row (MikroORM's documentation writes @Property() title!: string).

Safer Alternatives

Most ! can be replaced by something the compiler checks, or by a check that fails loudly at the right place:

Both helpers narrow the type like ! does, but a wrong assumption produces missing HOST on the spot instead of a TypeError somewhere else. assertDefined is an assertion function (asserts value is ...): after the call, the compiler treats host as a string. More patterns in type guards.

Instead ofWriteWhat happens when the value is missing
user!.nameif (user) { user.name }the block is skipped
user!.nameuser?.nameundefined
count!count ?? 0the default is used
map.get(k)!must(map.get(k), "k")a clear error at that line
let x!: Tconst x = compute()nothing to go wrong

The Other Exclamation Marks

! means different things depending on where it sits:

CodeMeaning
value! (after an expression)non-null assertion, TypeScript only
let x!: T, prop!: Tdefinite assignment assertion, TypeScript only
!value (before an expression)logical NOT, plain JavaScript
!!valueconverts to a boolean, plain JavaScript
a !== b, a != binequality, plain JavaScript

Only the first two are erased at compile time. !value and !!value run at runtime and return a boolean.

Frequently Asked Questions

What does an exclamation mark after a variable mean in TypeScript?

value! is the non-null assertion operator. It tells the compiler that value is not null or undefined, so its type loses those two members: string | undefined becomes string. It is removed from the emitted JavaScript and adds no runtime check, so if you are wrong the program fails later with a TypeError.

What is the difference between ! and ? in TypeScript?

x! asserts the value is present and gives you the non-null type, with no check. x?.y checks at runtime: if x is null or undefined it stops and returns undefined. In a declaration, name?: string makes a property optional, while name!: string says a required property will be assigned somewhere the compiler cannot see.

What does let x!: string mean?

It is a definite assignment assertion. It tells the compiler the variable will be assigned before it is read, even though the compiler cannot prove it (for example, the assignment happens inside another function). Without it, reading the variable is error TS2454, Variable 'x' is used before being assigned.

How do I fix "has no initializer and is not definitely assigned in the constructor"?

That is error TS2564 from strictPropertyInitialization. Give the property an initial value, assign it in the constructor, make it optional (prop?: T), or, if a framework or an init method really sets it before use, write prop!: T. The ! is the last option because nothing checks the promise.

Is the non-null assertion operator bad practice?

It is not wrong, but each ! is an unchecked claim. Lint setups such as @typescript-eslint/no-non-null-assertion flag it. Prefer a check that narrows (if (x), x ?? fallback, x?.y) or a helper that throws a clear error. Keep ! for places where the value is guaranteed by logic the compiler cannot follow.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED