¿Cuál es la diferencia entre `interface` y `type` en TypeScript? ¿Cuál usas y por qué?
Ver respuesta — intenta responderla en voz alta primero
Ambos sirven para describir la forma de un objeto y en la práctica son intercambiables en el 90% de los casos. Las diferencias reales: interface soporta declaration merging y se extiende con extends; type es más flexible porque también representa uniones, tuplas y alias de primitivos. Lo importante es ser consistente en el proyecto.
Para describir un objeto, los dos funcionan igual de bien:
- Extender:
interfaceusaextends;typeusa la intersección&. El resultado es equivalente para objetos. - Declaration merging: si declaras dos
interfacecon el mismo nombre, TypeScript las fusiona. Contypeeso es un error (nombre duplicado). El merging es útil sobre todo en librerías, para que quien las usa pueda ampliar tipos globales. - Solo
type: uniones ("a" | "b"), tuplas ([number, number]), alias de primitivos (type Id = string) y tipos calculados con utility types complejos.
¿Qué conviene? Una convención común es: interface para la forma de objetos públicos (props, modelos) y type para uniones y composiciones. Otra igual de válida: type para todo. Como en la práctica da casi igual, la respuesta madura en entrevista es que sigues la convención del equipo.
// Ambos describen la misma forma de objeto
interface UsuarioInterface {
nombre: string;
edad: number;
}
type UsuarioType = {
nombre: string;
edad: number;
};
// Extender: extends vs intersección &
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: solo con interface
interface Config { url: string; }
interface Config { timeout: number; }
// TypeScript las fusiona: Config = { url: string; timeout: number }
const config: Config = { url: "/api", timeout: 3000 };
// Cosas que SOLO puede hacer type
type Estado = "cargando" | "listo" | "error"; // unión
type Coordenada = [number, number]; // tupla
type Id = string; // alias de primitivo
Intentar usar type para una unión... con interface:
// Error: An interface can only extend an object type...
// interface Estado = "cargando" | "listo";
// Una interface no puede representar una unión. Para eso, type:
type Estado = "cargando" | "listo";
Otro tropiezo: pensar que la diferencia es enorme y dudar en cada archivo. En objetos normales son intercambiables; perder tiempo decidiendo en cada caso es peor que elegir una convención y mantenerla.
"Para describir objetos,
interfaceytypeson prácticamente intercambiables. Las diferencias concretas son tres: interface se extiende conextendsy type con la intersección&; interface soporta declaration merging, que se usa sobre todo para ampliar tipos de librerías; y type puede representar cosas que interface no, como uniones, tuplas o alias de primitivos. En mi día a día uso type para uniones y composiciones, y para objetos sigo la convención del proyecto, porque lo importante es ser consistente."
Modela esto: un Producto tiene nombre (string) y precio (number). Un ProductoDigital es un Producto con urlDescarga (string). Además, define Categoria que solo puede ser "libro", "curso" o "plantilla". Usa interface donde se pueda y type donde sea obligatorio.
Ver solución
interface Producto {
nombre: string;
precio: number;
}
interface ProductoDigital extends Producto {
urlDescarga: string;
}
// La unión de literales solo se puede expresar con 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";