What is the difference between `interface` and `type` in TypeScript? Which one do you use and why?
Show answer — try answering out loud first
Both are used to describe the shape of an object, and in practice they're interchangeable in 90% of cases. The real differences: interface supports declaration merging and is extended with extends; type is more flexible because it can also represent unions, tuples, and aliases of primitives. What matters is being consistent within the project.
To describe an object, both work equally well:
- Extending:
interfaceusesextends;typeuses the intersection&. The result is equivalent for objects. - Declaration merging: if you declare two
interfaces with the same name, TypeScript merges them. Withtypethat's an error (duplicate name). Merging is useful mostly in libraries, so that consumers can extend global types. - Only
type: unions ("a" | "b"), tuples ([number, number]), aliases of primitives (type Id = string), and types computed with complex utility types.
Which is better? A common convention is: interface for the shape of public objects (props, models) and type for unions and compositions. Another equally valid one: type for everything. Since in practice it barely matters, the mature answer in an interview is that you follow the team's convention.
// Both describe the same object shape
interface UsuarioInterface {
nombre: string;
edad: number;
}
type UsuarioType = {
nombre: string;
edad: number;
};
// Extending: extends vs intersection &
interface Admin extends UsuarioInterface {
permisos: string[];
}
type Moderador = UsuarioType & {
seccion: string;
};
const admin: Admin = { nombre: "Ana", edad: 30, permisos: ["borrar"] };
const mod: Moderador = { nombre: "Luis", edad: 28, seccion: "foros" };
// Declaration merging: only with interface
interface Config { url: string; }
interface Config { timeout: number; }
// TypeScript merges them: Config = { url: string; timeout: number }
const config: Config = { url: "/api", timeout: 3000 };
// Things that ONLY type can do
type Estado = "cargando" | "listo" | "error"; // union
type Coordenada = [number, number]; // tuple
type Id = string; // alias of a primitive
Trying to use type for a union... with interface:
// Error: An interface can only extend an object type...
// interface Estado = "cargando" | "listo";
// An interface can't represent a union. For that, use type:
type Estado = "cargando" | "listo";
Another stumble: thinking the difference is huge and hesitating in every file. For normal objects they're interchangeable; wasting time deciding case by case is worse than picking a convention and sticking to it.
"To describe objects,
interfaceandtypeare practically interchangeable. There are three concrete differences: interface is extended withextendsand type with the intersection&; interface supports declaration merging, which is used mostly to extend library types; and type can represent things interface can't, like unions, tuples, or aliases of primitives. In my day-to-day I use type for unions and compositions, and for objects I follow the project's convention, because what matters is being consistent."
Model this: a Producto has nombre (string) and precio (number). A ProductoDigital is a Producto with urlDescarga (string). Also, define Categoria that can only be "libro", "curso", or "plantilla". Use interface where you can and type where it's required.
See solution
interface Producto {
nombre: string;
precio: number;
}
interface ProductoDigital extends Producto {
urlDescarga: string;
}
// The union of literals can only be expressed with type
type Categoria = "libro" | "curso" | "plantilla";
const ebook: ProductoDigital = {
nombre: "Guía de TypeScript",
precio: 15,
urlDescarga: "/descargas/guia-ts.pdf",
};
const categoria: Categoria = "libro";