4.7 Non-Null Assertion Operator ! and When to Avoid It

Alright, let’s talk about the non-null assertion operator, !. This is the TypeScript equivalent of you yelling “I KNOW WHAT I’M DOING!” directly into the compiler’s ear. It’s a way to tell the type system, “Stop your whining. This value might look like it could be null or undefined, but I, the all-seeing developer, promise you it’s not.” You use it by putting an exclamation mark after an expression. It’s like a magic wand that instantly removes null and undefined from the type.

4.6 Optional Chaining ?. and Nullish Coalescing ??

Right, let’s talk about the two operators that single-handedly made JavaScript’s null and undefined problem slightly less of a headache. I’m talking about optional chaining (?.) and nullish coalescing (??). These aren’t just syntactic sugar; they’re a fundamental shift in how we write defensive code, moving from clunky, repetitive guard clauses to something approaching elegance. Before they existed, checking for a deeply nested property was a soul-crushing exercise in if statements or ternary operators. You’d write a novel just to see if user.address.zipCode existed. It was ugly, error-prone, and frankly, boring. These operators are the language’s long-overdue apology for that.

4.5 Narrowing to never: The Completeness Pattern

Right, so you’ve met never. It’s TypeScript’s way of telling you that something should literally, physically never happen. It’s the type of a function that throws an error forever, or a variable that can’t possibly have a value. It feels abstract, but it has one killer app that will save your bacon: exhaustive checking. Think of never as the empty set in mathematics. If a string is a bag full of all possible text, and number is a bag of all possible integers and floats, then never is a completely empty bag. You can assign never to anything because an empty bag can be put inside any other bag (let n: never; let s: string = n; is valid). But you can’t assign anything to never (except another never) because you can’t put a real value into an empty bag without breaking the universe. This property is what makes it so useful for narrowing.

4.4 The never Type: Unreachable Code and Exhaustive Checks

Right, let’s talk about never. It’s the type that sounds the most dramatic and, frankly, a little bit emo. It’s the type system’s way of saying, “This path of code? Yeah, nothing is ever coming back from there. Not a value, not a Promise, not even undefined. It’s a black hole for program execution.” You use never to represent two main scenarios: when a function never returns normally (it either throws an error or loops forever), and—far more importantly for your day-to-day code—to signal unreachable code for the sake of exhaustive type checking.

4.3 strictNullChecks: Why Null Was a Billion-Dollar Mistake

Right, let’s talk about the ghost in the machine. The concept of null was famously dubbed a “billion-dollar mistake” by its inventor, Tony Hoare. He’s not wrong. It’s the equivalent of handing you a beautifully wrapped box, you shaking it with anticipation, and then finding out it’s completely empty. Or worse, it’s a box that may or may not even exist. This ambiguity is the root of countless runtime errors, the infamous Cannot read property 'x' of null that has haunted web browsers since the dawn of time.

4.2 undefined and null: Two Flavors of Nothing

Right, so you’ve met undefined and null. You’re probably thinking, “Why on earth does one language need two ways to say ’nothing’?” It’s a fair question. The official, committee-approved answer is a load of semantic nonsense about intent. The real, historical answer is that JavaScript was designed in ten days, and this is one of the warts that stuck. Don’t worry, we’ll make sense of it. Think of them as two distinct flavors of nothing: undefined is the nothing you get by accident, and null is the nothing you assign on purpose.

4.1 void: Functions That Return Nothing

Right, let’s talk about void. It sounds so final, doesn’tt it? Like a cosmic emptiness. But in TypeScript, it’s far less dramatic and far more practical. I use void for one specific job: to annotate a function that doesn’t return a useful value. It’s the type system’s way of saying, “This function is called for its side effects, not for what it gives back.” Think of a function that updates the DOM, writes to a console, or saves data to a database. You don’t call console.log('error!') because you want to use its return value (which is undefined, by the way); you call it because you want the effect of a message appearing in your console. That’s the void territory.

— joke —

...