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
59: Path Aliases and Module Resolution
I once spent an entire Friday afternoon refactoring a folder structure in a large e-commerce dashboard. I moved a few shared UI components into a new common folder, and suddenly my IDE was screaming. I had about forty files with imports like ../../../../components/Button that all needed to be updated. It's tedious, error-prone work that adds zero value to the product, and it's a sign that the project has outgrown relative imports.
When your project grows, you start seeing these "staircases of dots" at the top of your files. Not only are they hard to read, but they make moving files a nightmare. This is where path aliases come in. They allow you to define a shorthand—like @components—that always points to a specific directory, regardless of where the file you're currently editing is located in the folder hierarchy.
Mapping the Project Landscape
To set this up, we head into the tsconfig.json. There are two keys you need to care about: baseUrl and paths. The baseUrl acts as the root for non-relative module names. Usually, you'll set this to . (the current directory) or ./src.
Once the base is set, you can define the paths object. This is essentially a dictionary where the key is the alias and the value is an array of paths where TypeScript should look for those modules. Here is how I typically set up a professional project:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@models/*": ["src/core/models/*"],
"@services/*": ["src/core/services/*"],
"@ui/*": ["src/components/ui/*"],
"@utils/*": ["src/lib/utils/*"]
}
}
}
Now, instead of typing import { User } from "../../../core/models/user.model", you can simply write import { User } from "@models/user.model". It's cleaner, it's more intentional, and if you move the consuming file to a completely different folder, the import doesn't break.
Bridging the Gap to Runtime
Here is the "gotcha" that trips up almost everyone the first time they do this: TypeScript does not rewrite these paths when it compiles your code to JavaScript. TS is a type-checker; it's happy as long as it can find the file to verify the types. However, when the resulting JS runs in Node or a browser, the environment has no idea what @models means. It will throw a "Module not found" error.
Depending on your stack, you have to tell your runtime how to resolve these aliases too. If you're using Vite or Webpack, you'll add a corresponding alias section to their config files. If you're running raw Node with ts-node, you'll likely need the tsconfig-paths package. I usually recommend keeping your tsconfig and your bundler config in sync—if you add an alias to one, add it to the other immediately so you don't spend an hour debugging a runtime crash that the compiler told you was perfectly fine.
📋 Practical Task
Exercise: Flattening the Nested Import Structure of a User Dashboard
You have been handed a legacy TypeScript project with a messy directory structure. You need to implement path aliases to clean up the imports in a deeply nested component.
Current Structure:
/src
/core
/api
api-client.ts
/features
/dashboard
/components
/widgets
UserStats.tsx
The Goal:
In UserStats.tsx, the current import is:
import { apiClient } from "../../../../core/api/api-client";
Your Tasks:
- Modify the
tsconfig.jsonto establish abaseUrlof".". - Create a path alias called
@api/*that maps tosrc/core/api/*. - Rewrite the import statement in
UserStats.tsxto use the new alias.
Deliverable: Provide the compilerOptions block of your tsconfig.json and the updated import line from UserStats.tsx.
There are no comments for now.