Skip to Content
Course content

53: Strict Mode and Compiler Flags

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I want to show you something that usually happens about three months into a professional TypeScript project. You start with a configuration that feels "easy," everything compiles, and you're moving fast. Then, one Tuesday, you get a production error—a TypeError: Cannot read property 'toLowerCase' of undefined—and you realize that TypeScript was actually letting you write dangerous code all along.

Living in the Danger Zone

Let's look at a piece of code I wrote for a user profile system. I've got a simple interface and a function to format a user's display name. Right now, my tsconfig.json is pretty relaxed—I haven't touched the strict flags yet.

interface UserProfile {
  username: string;
  displayName?: string; // Optional
}

function formatDisplayName(user: UserProfile) {
  // I'm assuming if displayName is missing, I'll just use username
  const name = user.displayName || user.username;
  return name.trim().toUpperCase();
}

const userA = { username: "jdoe123", displayName: "John Doe" };
const userB = { username: "smith_99" };

console.log(formatDisplayName(userA)); // "JOHN DOE"
console.log(formatDisplayName(userB)); // "SMITH_99"

This looks fine, right? It compiles without a single red squiggly line. But here's the problem: I'm playing a guessing game. I'm trusting that name will always be a string. If for some bizarre reason user.username was also undefined (maybe due to a bad API response), the whole app crashes. TypeScript isn't warning me because, by default, it's being "nice."

Flipping the Switch

Now, let's stop being nice. I'm going into my tsconfig.json and adding one single line: "strict": true.

{
  "compilerOptions": {
    "strict": true,
    "target": "ESNext",
    "module": "CommonJS"
  }
}

The moment I save this file, my editor explodes with errors. Suddenly, the formatDisplayName function is underlined in red. Specifically, name.trim() is complaining. Why? Because strict: true is actually a bundle of flags. The big one hitting me here is strictNullChecks.

TypeScript is now telling me: "Hey, you said displayName is optional. Even though you have a fallback to username, what if both are missing? You can't call .trim() on something that might be undefined."

Wrestling with Nulls

I can't just ignore this. I have to prove to the compiler that I've handled the empty case. I'll try a type guard first to see if that satisfies the compiler.

function formatDisplayName(user: UserProfile) {
  const name = user.displayName || user.username;

  if (!name) {
    return "Anonymous";
  }

  // Now TypeScript knows 'name' cannot be null or undefined here
  return name.trim().toUpperCase();
}

That fixed it. By adding that if (!name) check, I've "narrowed" the type. I've essentially told TypeScript: "I've handled the scary stuff, you can relax now." This is the core philosophy of strict mode: it forces you to handle the edge cases before they happen in production.

Closing the 'Any' Loophole

While I'm in here, let's look at another flag included in the strict bundle: noImplicitAny. I'll add a quick helper function to my code to see how it behaves.

function logUser(user, message) {
  console.log(`${message}: ${user.username}`);
}

Without strict mode, TypeScript just assumes user and message are of type any. It doesn't complain, but it also doesn't help me. With strict: true, this is now an error. It's telling me that it can't infer the type, and since I didn't provide one, it's refusing to guess.

I could just type them as any to make the error go away, but that's cheating. The whole point of using TypeScript is to avoid any. I'll give them proper types instead:

function logUser(user: UserProfile, message: string) {
  console.log(`${message}: ${user.username}`);
}

It feels like more work upfront, but I've just eliminated two potential bugs: passing a number instead of a string for the message, and passing an object that doesn't actually have a username property. When you turn on strict mode, you stop treating TypeScript as a suggestion and start treating it as a contract.




📋 Practical Task

Hardening the Product Discount Calculator

You have been handed a legacy piece of code for an e-commerce store. The current tsconfig.json has "strict": false, and the code is riddled with potential runtime crashes. Your goal is to harden this code.

Your Task:

  1. Assume "strict": true is now enabled in the compiler settings.
  2. Fix the calculateDiscount function below so that it compiles without errors.
  3. You must handle the case where discountRate is missing (default it to 0).
  4. You must ensure price is a valid number before performing calculations.
  5. Remove any implicit any types by explicitly defining the types for the function parameters.
interface Product {
  name: string;
  price?: number;
  discountRate?: number;
}

function calculateDiscount(product, label) {
  // TODO: Fix this function to work under "strict": true
  const finalPrice = product.price * (1 - product.discountRate);
  return `${label}: ${finalPrice}`;
}

const laptop = { name: "Gaming Laptop", price: 1200, discountRate: 0.1 };
const mouse = { name: "Wireless Mouse" }; // Missing price and discountRate

console.log(calculateDiscount(laptop, "Sale Price"));
console.log(calculateDiscount(mouse, "Sale Price"));
Rating
0 0

There are no comments for now.

to be the first to leave a comment.