TypeScript: Interface vs. Type — Don't Overthink It (Too Much)
You're grinding through TypeScript interview prep, probably staring at a LeetCode problem or a simulated coding challenge, and then it hits you: "Should I use interface or type here?" This isn't just a casual thought; it's a common stumbling block in TypeScript interviews, especially at companies that really lean into strongly typed codebases. The truth is, for most practical applications, the distinction is less critical than you might think, but understanding the nuances can definitely make you sound smarter in a technical discussion.
Most of the time, when you're defining an object shape, an interface works perfectly fine. You'll declare interface User { id: string; name: string; } and move on with your life. It's concise, readable, and TypeScript's compiler is incredibly optimized for it.
Where type starts to shine is when you're doing things that an interface simply can't do. Think union types (type ID = string | number;), intersection types (type AdminUser = User & { role: 'admin' };), or defining aliases for primitive types or complex utility types. You can't say interface ID = string | number; – that's just not how interfaces operate. They're primarily for describing object shapes and class contracts.
The extensibility argument often comes up: interface declarations merge automatically. If you define interface User { name: string; } in one file and then interface User { email: string; } in another, TypeScript effectively combines them into interface User { name: string; email: string; }. This is fantastic for declaration merging, like when you're augmenting third-party library types or extending global objects. It’s a powerful feature, but also one that can lead to unexpected behavior if you're not careful about where and how you're defining your interfaces.
Type aliases, on the other hand, don't merge. If you have type User = { name: string; } and then try to declare type User = { email: string; } again, you'll get a duplicate identifier error. This explicit non-merging behavior can be a huge benefit for maintainability, as it ensures that a type's definition is always in one place, making it easier to track changes and prevent accidental overwrites. This predictability is often why many teams adopt a "prefer type unless you need interface for specific reasons" rule.
When interface is Your Go-To
You absolutely must use interface when you're defining the shape of a class. A class can implement an interface, guaranteeing that it adheres to a specific contract. This is a core OOP concept that type aliases can't replicate directly. For example, class MyLogger implements LoggerInterface { ... } is perfectly valid, while class MyLogger implements LoggerTypeAlias { ... } will throw an error. This is a crucial distinction for designing extensible architectures, especially in larger applications or when working with frameworks that rely heavily on inversion of control.
Another strong case for interfaces is when you’re building public APIs or library definitions. The declaration merging behavior can be incredibly useful for allowing consumers of your library to augment types without having to fork or modify your original source. Imagine a plugin system where each plugin adds properties to a global configuration object; interface merging makes this incredibly elegant. You'll see this extensively in popular libraries like Express or React.
When type Takes the Lead
As mentioned, complex type operations are type's playground. Consider a scenario where you have a User type and you want to create a UserWithPermissions type that adds a permissions array, but also potentially extends it with other properties from a MetaData type. You'd write type UserWithPermissions = User & { permissions: string[] } & MetaData;. This kind of intersection is straightforward with type.
You'll also reach for type when you need to alias primitive types or literal types. type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; is a common pattern for type-safe enums without using actual enums. Similarly, type Milliseconds = number; provides semantic meaning to a bare number type, improving code readability without introducing runtime overhead. These aliases can make your code much more expressive and self-documenting.
The Interviewer's Angle
Interviewers aren't usually looking for you to declare a religious war between interface and type. They want to see that you understand the fundamental differences and, more importantly, why you'd choose one over the other in specific scenarios. If you can explain the declaration merging of interface or the union/intersection capabilities of type, you're demonstrating a solid grasp of TypeScript's type system.
A good answer might involve acknowledging that for simple object shapes, either is often fine. Then, pivot to the edge cases: "I'd lean towards interface if I'm defining a class contract or expect external modules to augment this type. Otherwise, for union types, intersection types, or simply aliasing a primitive, type is my choice." This shows flexibility and awareness, not rigid adherence to a single rule.
My Slightly Opinionated Take
In most modern, well-structured codebases, you'll see a slight preference for type. The explicit non-merging behavior and ability to handle complex type transformations often make it a safer and more versatile default. I personally tend to reach for type first, unless I explicitly need interface for class implementations or declaration merging. This approach keeps things consistent and reduces surprises.
However, this isn't a hard-and-fast rule. If you're joining a project that's 90% interface, just go with the flow. Consistency within a codebase trumps any minor theoretical advantage of one over the other. The key is to be adaptable and understand the reasoning behind existing patterns. Don't be the engineer who tries to refactor hundreds of interfaces to types just because you read an article.
Ready to Ace Your Next Interview?
Practice with AI-powered mock interviews tailored to your target role and company. Start Practicing for Free | Explore Interview Prep
