-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
90: Understanding strict, strictNullChecks, and noImplicitAny
I often see developers treat the strict flag in tsconfig.json as a "hard mode" setting—something you turn on once you've "mastered" the language, or something you disable when you're in a rush to ship a feature. The biggest misconception I encounter is the belief that these strict checks are just about adding more boilerplate or satisfying a pedantic compiler, rather than actually preventing production crashes.
"It's just more typing" vs. preventing the billion-dollar mistake
Let's look at a concrete example. Imagine you're building a user profile page. You have a User interface where the bio is optional because not every user writes one.
interface User {
username: string;
bio?: string;
}
function getBioLength(user: User) {
return user.bio.length;
}
If strictNullChecks is off, TypeScript looks at this and says, "Looks good to me!" It assumes that if you're accessing bio, it's probably there. But the moment a user without a bio hits that function, your app crashes with TypeError: Cannot read property 'length' of undefined. This is exactly what Tony Hoare called the "billion-dollar mistake."
When you turn strictNullChecks on, TypeScript stops being "polite" and starts being helpful. It will red-line user.bio.length and tell you that the object is possibly undefined. Now, you're forced to handle that case—either with an optional chain (user.bio?.length) or a proper if-statement. I'd much rather spend three seconds adding a question mark now than three hours debugging a production outage later.
Stopping the "accidental any" leak
Then we have noImplicitAny. A common frustration I hear is: "I know it's an any, why does TypeScript care if I don't explicitly say so?"
The issue isn't that any exists; the issue is when any sneaks into your codebase without you noticing. Consider this function:
function processOrder(order) {
console.log(order.id);
}
Without noImplicitAny, TypeScript just gives up on the order parameter and implicitly types it as any. You've now created a hole in your type safety. If you later change the Order object to use order.uuid instead of order.id, TypeScript won't warn you here. You've essentially opted out of the whole point of using TypeScript for this function.
By enabling noImplicitAny, the compiler forces you to be intentional. You either define the type, or—if you truly don't know the type—you explicitly write any. That explicit any acts as a red flag for your future self (and your teammates) that this specific spot is a potential weak point in the system.
The master switch: Why 'strict' is the only flag you need
You might be tempted to just cherry-pick strictNullChecks and noImplicitAny and leave the rest. I strongly advise against this. Setting "strict": true is a master switch that enables a suite of checks, including strictPropertyInitialization (which ensures you don't forget to assign values to class properties in the constructor) and strictFunctionTypes.
I think of strict: true as the "professional standard." When you're working on a team, having a consistent strictness level ensures that everyone is held to the same safety standards. If you start with a loose config and try to tighten it up six months into a project, you'll find yourself staring at 5,000 errors and a weekend of misery. Start strict, stay strict.
📋 Practical Task
Fixing the Fragile Product Catalog
You've inherited a small module for a product catalog. The previous developer had strict mode turned off, and now that you've enabled it in the tsconfig.json, the project is full of errors. Your goal is to fix the type safety issues without using any to bypass the errors.
interface Product {
id: number;
name: string;
description?: string; // Optional
price: number;
}
function printProductDetails(product: Product) {
// ERROR: Object is possibly 'undefined'
console.log("Description: " + product.description.toUpperCase());
}
function applyDiscount(product: Product, discount) {
// ERROR: Parameter 'discount' implicitly has an 'any' type
return product.price - discount;
}
class Catalog {
products: Product[];
constructor() {
// ERROR: Properties of class 'Catalog' have no initializer
// and are not definitely assigned in the constructor.
}
addProduct(p: Product) {
this.products.push(p);
}
}
// Test cases
const laptop: Product = { id: 1, name: "Laptop", price: 1200 };
printProductDetails(laptop);
console.log(applyDiscount(laptop, 100));
Your task:
- Fix the
printProductDetailsfunction so it handles the optionaldescriptionsafely. - Provide a proper type for the
discountparameter inapplyDiscount. - Fix the
Catalogclass so theproductsarray is properly initialized.
There are no comments for now.