TypeScript Types and Interfaces — What's the Difference?
One of the first questions TypeScript developers hit is: should I use type or interface? They look almost identical on the surface, and for simple cases they're interchangeable. But each has a niche where it genuinely shines.
Defining Object Shapes — Both Work
// Using interface
interface User {
id: number;
name: string;
email: string;
}
// Using type alias
type User = {
id: number;
name: string;
email: string;
};For simple object shapes, the choice is mostly stylistic. Here's how to think about when to pick one.
Interfaces Are for Contracts
Interfaces are ideal when you're describing a contract — something a class or object must conform to. They support declaration merging, which is useful when working with third-party libraries.
interface Repository<T> {
findById(id: string): Promise<T | null>;
save(entity: T): Promise<T>;
delete(id: string): Promise<void>;
}
class UserRepository implements Repository<User> {
async findById(id: string) { /* ... */ }
async save(user: User) { /* ... */ }
async delete(id: string) { /* ... */ }
}Type Aliases Are for Unions and Computed Types
type becomes necessary when you need union types, intersection types, or any computed/conditional type:
// Union type — only possible with type
type Status = "idle" | "loading" | "success" | "error";
// Intersection type
type AdminUser = User & { permissions: string[] };
// Conditional type
type NonNullable<T> = T extends null | undefined ? never : T;
// Mapped type
type ReadOnly<T> = {
readonly [K in keyof T]: T[K];
};You can't express these with interface.
The Practical Rule
- Use
interfacefor object shapes that represent real-world entities (User, Product, ApiResponse) - Use
typefor unions, intersections, utility types, and function signatures - Be consistent within a codebase — pick one default and only switch when the other is strictly necessary
// Recommended pattern
interface BlogPost {
id: string;
title: string;
status: PostStatus; // using the type alias from below
}
type PostStatus = "draft" | "published" | "archived";
type PostWithAuthor = BlogPost & { author: User };In Part 3, we'll look at generics — the feature that makes TypeScript's type system truly powerful for building reusable utilities.
TypeScript Series