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
12: Type Aliases
I've seen this happen in almost every codebase I've joined. A developer starts with a simple object, and as the feature grows, that object shape gets passed around to five different functions. It looks something like this:
function createUser(id: number, name: string, email: string) {
return { id, name, email };
}
function sendWelcomeEmail(user: { id: number, name: string, email: string }) {
console.log(`Sending email to ${user.email}...`);
}
function updateProfile(user: { id: number, name: string, email: string }, newName: string) {
return { ...user, name: newName };
}
The maintenance trap of inline types
At first, this seems fine. But then, the product manager asks you to add a phoneNumber field to the user. You update createUser and sendWelcomeEmail, but you forget about updateProfile because it's buried in another file. Suddenly, TypeScript starts screaming at you—or worse, you have a runtime bug because the data flowing into updateProfile doesn't match what the function expects.
Repeating the same object literal { id: number, name: string, email: string } everywhere is a recipe for disaster. It's tedious to write, and it's a nightmare to maintain. If you change the type in one place, you have to hunt down every single instance of that shape across your entire project.
Giving your shapes a name
This is where type aliases come in. Instead of defining the shape inline every time, we create a "nickname" for that type using the type keyword. It doesn't create any actual JavaScript code when it compiles; it's purely a label for the TypeScript compiler to use.
type User = {
id: number;
name: string;
email: string;
phoneNumber?: string; // Now we can add this in one place
};
function createUser(id: number, name: string, email: string): User {
return { id, name, email };
}
function sendWelcomeEmail(user: User) {
console.log(`Sending email to ${user.email}...`);
}
function updateProfile(user: User, newName: string): User {
return { ...user, name: newName };
}
Now, the User type is the single source of truth. If the requirements change again, you change it once in the alias, and every function using User is automatically updated. It makes the function signatures much cleaner and easier to read at a glance.
Handling "this or that" with Union Aliases
Type aliases aren't just for objects. In fact, one of the most powerful ways I use them is for union types. Imagine you're building a system that handles different types of notifications. You might have a status that can only be one of three specific strings.
Writing status: 'pending' | 'approved' | 'rejected' everywhere is clunky. Instead, do this:
type RequestStatus = 'pending' | 'approved' | 'rejected';
type Notification = {
id: string;
message: string;
status: RequestStatus;
};
const myNote: Notification = {
id: '123',
message: 'Your request is being reviewed',
status: 'pending' // TypeScript will autocomplete this for you!
};
I personally love this because it turns "magic strings" into a formal type. If you typo 'pendng', TypeScript catches it immediately. Without the alias, you're just guessing and hoping you spelled the string correctly in every single file.
📋 Practical Task
Refactoring the E-Commerce Order System
You've inherited a messy piece of code for an e-commerce checkout. Currently, the types for Product and Order are defined inline, and the order status is repeated as a union of strings in multiple places. Your task is to refactor this using Type Aliases to make it maintainable.
// Current broken/messy state:
function calculateTotal(items: { id: string, price: number, quantity: number }[]) {
return items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
}
function shipOrder(order: { id: string, items: { id: string, price: number, quantity: number }[], status: 'processing' | 'shipped' | 'delivered' }) {
console.log(`Shipping order ${order.id}...`);
}
function updateOrderStatus(order: { id: string, items: { id: string, price: number, quantity: number }[], status: 'processing' | 'shipped' | 'delivered' }, newStatus: 'processing' | 'shipped' | 'delivered') {
return { ...order, status: newStatus };
}
Requirements:
- Create a
Producttype alias for the item shape. - Create an
OrderStatustype alias for the status union. - Create an
Ordertype alias that utilizes bothProductandOrderStatus. - Update the three functions to use these aliases instead of the inline definitions.
There are no comments for now.