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
19: Interfaces vs Type Aliases
They both seem to do the same thing for objects—does it actually matter which one I pick?
If you're just defining the shape of a simple object, honestly? No, it doesn't matter much. You can use interface or type and the code will behave exactly the same way. But as you start building larger systems, the intent changes.
I tend to think of an interface as a "contract." It defines a blueprint for what an object should look like. A type alias, on the other hand, is exactly what it sounds like: an alias. It's just a nickname for any type definition, whether that's an object, a primitive, or a complex union.
// This is a contract. I'm saying "any object that claims to be a User must have these" interface User { id: string; username: string; } // This is an alias. I'm saying "whenever I say 'UserID', I actually mean a string" type UserID = string; // You can also use type for the object shape, and it works fine type UserAccount = { id: UserID; email: string; };I keep hearing about "declaration merging." Why is that useful?
This is one of the biggest technical differences. Interfaces are "open," meaning if you declare the same interface twice, TypeScript automatically merges them into one. Types are "closed"—once you define a type, you can't just add more properties to it later by declaring it again.
You won't use this every day, but it's a lifesaver when you're working with third-party libraries. Imagine you're using a library that defines a
Windowinterface, but you've added a custom analytics object to the global window in your project. You can't edit the library's code, but you can "reopen" the interface in your own file:// The library defines this interface Window { localStorage: Storage; } // I can "merge" my own property into it without touching the library interface Window { myCustomAnalytics: (event: string) => void; } // Now TS knows both properties exist on window window.myCustomAnalytics('page_view');Can I do everything with an interface?
Nope. This is where
typealiases really shine. Interfaces are limited to describing object shapes. Types can describe anything. The most common scenario where you'll need a type is for Union Types—when a value could be one of several different things.If you're building a payment system, you might have a status that can only be a few specific strings. You can't do that with an interface.
// This is impossible with an interface type PaymentStatus = 'pending' | 'completed' | 'failed' | 'refunded'; interface Order { id: string; status: PaymentStatus; // Using the type alias here } const myOrder: Order = { id: 'ord_123', status: 'completed' // TS will error if I type 'shipped' };I usually follow a simple rule of thumb: start with
interfacefor your object structures and data models. The moment you need a union, a tuple, or a primitive alias, switch totype.
📋 Practical Task
Refactoring the E-Commerce Product Schema
You are working on a product catalog. Currently, the developer used type for everything, but the codebase is growing. Your goal is to refactor the code to use interface for the object blueprints and type for the specific constraints.
Requirements:
- Change the
Productdefinition from atypeto aninterface. - Create a
typealias calledProductCategorythat is a union of:'Electronics','Clothing', and'Home'. - Update the
Productinterface to useProductCategoryfor itscategoryproperty. - Demonstrate declaration merging by creating a second
Productinterface declaration that adds an optionaldiscountPriceproperty (number).
Your final code should allow a product object to have an id, name, category (restricted to the union), and the merged discountPrice.
There are no comments for now.