TypeScript
Completed
-
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
5: TypeScript in VS Code
If you've used VS Code for JavaScript, you already know it's a great editor. But when you move to TypeScript, there is a massive difference between using VS Code as a fancy text editor and using it as a full-blown development environment. I see this a lot with developers moving from other languages; they treat the IDE as a place to type, and the terminal as the place where the "actual" work of checking types happens.
The "Run and Pray" Workflow
The naive way to approach this is to just create a .ts file, write some code, and run tsc or ts-node in your terminal to see if it works. Imagine you're building a small system to manage a library's book inventory. You've got a Book interface and a function to check if a book is overdue. In the naive workflow, you write your logic, hit save, switch to the terminal, run the compiler, and then—if you're lucky—you get a list of errors that you then have to map back to the line numbers in your code.
// bookManager.ts
interface Book {
title: string;
dueDate: Date;
}
function isOverdue(book: Book) {
return book.dueDate < new Date();
}
const myBook = { title: "The TypeScript Guide", due_date: new Date() };
isOverdue(myBook); // You don't notice the typo 'due_date' until you run the compiler.
This approach costs you cognitive load. You're constantly context-switching between your code and your terminal. It breaks the moment your project grows beyond a single file because you're manually managing the compilation of individual files rather than treating the project as a cohesive unit.
Bridging the Gap with tsconfig.json
The better way is to realize that VS Code isn't just displaying your code—it's running a TypeScript language server in the background. The secret to making this server actually useful is the tsconfig.json file. Without it, VS Code makes a lot of guesses about how to treat your files, and those guesses often differ from how the tsc command-line tool behaves. This is where the "it works in my editor but fails in the build" frustration comes from.
When you add a tsconfig.json with "strict": true, you're essentially telling VS Code: "Stop being polite and start being pedantic." Suddenly, those red squiggles appear the millisecond you make a mistake. In the library example above, the moment you typed due_date instead of dueDate, VS Code would have flagged it. I usually tell my colleagues that if you're spending more than five seconds looking at your terminal to find a type error, you're using the tool wrong.
Navigating the Type Graph
Once you have the environment synced, you can stop reading your code linearly. In a real-world project, types can get deeply nested. Instead of scrolling up 200 lines to remember what properties a UserSession object has, you can just Cmd/Ctrl-click the type name. This "Go to Definition" feature is the single biggest productivity boost in TypeScript. I've spent hours of my career just jumping between definitions to trace how data flows through a system.
I also highly recommend getting comfortable with the "Quick Fix" menu (Cmd+. or Ctrl+.). If you have a type mismatch, don't just manually rewrite the variable. Use the Quick Fix to see if TypeScript can suggest a more appropriate type or a way to cast the value. It's a conversation with the compiler rather than a fight against it. You're moving from a cycle of "Write -> Compile -> Fix" to a real-time loop of "Write -> Correct -> Move On."
📋 Practical Task
Fixing the Library Inventory Type Mismatches
You have been handed a small project for a library system, but it's riddled with type errors that the compiler is complaining about. Your task is to use the VS Code "Problems" tab and "Quick Fix" features to resolve these issues without breaking the logic.
Setup: Create a folder with a tsconfig.json containing {"compilerOptions": {"strict": true}} and a file named inventory.ts with the following code:
interface Member {
id: string;
name: string;
membershipLevel: 'gold' | 'silver' | 'bronze';
}
interface Loan {
bookTitle: string;
memberId: string;
returnDate: Date | null;
}
function getMemberStatus(member: Member) {
// ERROR: Logic requires a string, but membershipLevel is a union
return `Member ${member.name} is ${member.membershipLevel.toUpperCase()}`;
}
const activeLoans: Loan[] = [
{ bookTitle: "TypeScript Deep Dive", memberId: "M123", returnDate: new Date() },
{ bookTitle: "Clean Code", memberId: "M456", returnDate: null }
];
function processReturn(loan: Loan) {
// ERROR: returnDate could be null
console.log("Processing return for: " + loan.returnDate.toDateString());
}
const newMember = { id: "M789", name: "Alice", membershipLevel: "platinum" };
getMemberStatus(newMember); // ERROR: 'platinum' is not a valid membershipLevel
Your Goal:
- Fix the
newMemberobject so it matches theMemberinterface. - Handle the potential
nullvalue inprocessReturnusing a type guard or optional chaining so thetoDateString()call is safe. - Verify that the "Problems" tab in VS Code is empty before saving.
There are no comments for now.