21.8 Adopting Strict Mode Incrementally

Right, so you’ve seen the light and want to turn on strict mode and its more discerning cousin, strictNullChecks. Good. But you’re not working in a greenfield project where you can just flip the switch and watch the world burn. You’re in the real world, with a codebase that has history, and that history is probably littered with any types and variables that are definitely null half the time. Trying to enable this for your entire project in one go is a recipe for 10,000 errors and a mutiny from your team. Let’s do this incrementally, like adults.

21.7 useUnknownInCatchVariables: Safer Error Handling

Let’s talk about the try...catch statement. You’ve used it, I’ve used it. We’ve all written code that looks like this, blissfully unaware of the TypeScript sin we’re committing: try { riskyOperation(); } catch (error) { // Look at me, I'm a good developer! I'm handling the error! console.error("Something went wrong:", error.message); // ...wait, what if `error` isn't an Error? Oops. } For years, the error in that catch clause was typed as any in TypeScript. It was a gaping hole in our type safety, a free pass to write error.somePropertyThatDefinitelyDoesntExist and have the compiler just shrug. It was the equivalent of the type system saying, “You’re on your own, pal. Good luck.”

21.6 noUncheckedIndexedAccess: Safer Array and Object Access

Right, so you’ve turned on strictNullChecks. Good for you. You’ve stopped lying to the compiler about null and undefined, and it’s started to trust you a bit more. But you’ve probably noticed a gaping hole in your defenses large enough to drive a truck through. You can still do this without so much as a peep from the type checker: const myArray: number[] = [1, 2, 3]; const element = myArray[5]; // TypeScript thinks this is a `number`. It's `undefined`. console.log(element.toFixed(2)); // 💥 Runtime error: Cannot read properties of undefined See? Absurd. We told TypeScript the array is full of numbers, so it assumes every single index access returns a number. It’s a lie, and we both know it. This is where noUncheckedIndexedAccess comes in. It’s the compiler’s way of saying, “Okay, fine, you want real safety? Let’s do this.”

21.5 strictPropertyInitialization: Class Fields Must Be Assigned

Right, so you’ve turned on strictNullChecks. Good for you. You’re no longer living in the wild west where undefined is a valid state for everything. But now you’re staring at a class like this, and TypeScript is yelling at you. Let’s talk about why. class UserAccount { name: string; // 💥 Error: Property 'name' has no initializer and is not definitely assigned in the constructor. isAdmin: boolean; } TypeScript’s strictPropertyInitialization rule is the hall monitor of your class properties. It demands that every instance property that doesn’t have undefined as part of its type must be assigned a value by the time the constructor function finishes. It’s not being pedantic for fun; it’s trying to save you from a runtime undefined error that would make you facepalm. Think of it this way: if the constructor doesn’t set it, and you haven’t promised it might be undefined, how on earth is it supposed to get a value?

21.4 strictFunctionTypes: Correct Function Variance

Now, let’s talk about the one that separates the TypeScript novices from the greybeards: strictFunctionTypes. This flag is the bouncer at the type-safe club, and it’s checking your function’s ID to make sure it’s not lying about its age. It enforces correct variance for function types, which is a fancy way of saying it makes sure your function parameters behave in a way that won’t blow up at runtime. Here’s the core of the issue. TypeScript uses structural typing (if it walks like a duck and talks like a duck, it’s a duck), but when it comes to function parameters, the safe thing to do is actually the opposite. It’s called contravariance. Hold on, don’t click away. I’ll make this painless.

21.3 noImplicitAny: Requiring Explicit any

Alright, let’s talk about noImplicitAny. This is the big one, the compiler flag that separates the TypeScript tourists from the residents. It’s the single most effective setting for turning your sloppy JavaScript-with-type-annotations project into something that actually earns the name “TypeScript.” Here’s the deal: by default, TypeScript is a people-pleaser. When it can’t figure out what type something should be, it throws its hands up and says, “Fine, fine, it’s any. Don’t hurt yourself.” It infers the type any. This is called an implicit any. It’s the compiler’s way of giving up and letting you do whatever you want, consequences be damned. Enabling noImplicitAny changes the rules. It tells the compiler, “No. I hired you to be a type checker, not a yes-man. If you can’t figure out a type, you have to raise an error and make the developer explicitly tell you it’s okay.” This forces you to either provide a proper type or consciously use the any keyword, acknowledging the escape hatch you’re using.

21.2 strictNullChecks: Making null and undefined Explicit

Alright, let’s talk about strictNullChecks. This is the single most important compiler flag in TypeScript, and if you have it turned off, you’re basically driving a car with the airbags disconnected because you find the warning light annoying. I’m not judging. Okay, I’m judging a little. Turn it on. Right now. I’ll wait. Without strictNullChecks, TypeScript treats null and undefined as valid values for every type. It’s the wild west. A string isn’t just a string; it’s a string that might also be null or undefined. This is, to use a technical term, bonkers. It completely undermines the entire point of using a type system to catch errors before they happen at runtime.

21.1 strict: The Umbrella Flag and What It Enables

Right, let’s talk about strict. You’ve probably seen it in a tsconfig.json file and wondered if it’s just a glorified “make my life harder” button. It’s not. It’s more like your brilliant but slightly pedantic friend who insists you wear a helmet while biking. Annoying? Sometimes. Life-saving? Absolutely. Think of strict not as a single rule, but as a curated bundle of other, more specific rules. It’s the master switch. When you set "strict": true in your tsconfig.json, you’re not enabling one thing; you’re enabling a whole family of incredibly useful, sanity-preserving options. The most famous of these are strictNullChecks and strictFunctionTypes, but the family is large and growing. The core philosophy is simple: turn on as many of these high-confidence checks as possible to catch bugs before they become runtime mysteries.

— joke —

...