Hasta ahora hemos visto tipos primitivos (string, number, boolean). Pero el mundo real funciona con objetos.
Usuarios, Productos, Pedidos… todos son objetos con múltiples propiedades.
La Anarquía de los Objetos Anónimos
En JavaScript puro, solemos pasar objetos de un lado a otro confiando en nuestra memoria.
function imprimirUsuario(usuario) {
// 🤞 Esperemos que 'usuario' tenga estas propiedades...
console.log("Nombre: " + usuario.name.toUpperCase());
console.log("Edad: " + usuario.age);
}
// Un mes después, alguien llama a la función así:
imprimirUsuario({ nombre: "Alice", edad: 30 });
// 💥 CRASH: Cannot read properties of undefined (reading 'toUpperCase')
// ¿Por qué? Porque pasamos "nombre" en español pero la función esperaba "name" en inglés.function imprimirUsuario(usuario) {
// 🤞 Esperemos que 'usuario' tenga estas propiedades...
console.log("Nombre: " + usuario.name.toUpperCase());
console.log("Edad: " + usuario.age);
}
// Un mes después, alguien llama a la función así:
imprimirUsuario({ nombre: "Alice", edad: 30 });
// 💥 CRASH: Cannot read properties of undefined (reading 'toUpperCase')
// ¿Por qué? Porque pasamos "nombre" en español pero la función esperaba "name" en inglés.TypeScript evita esto obligándonos a definir la FORMA (Shape) de nuestros objetos.
Interfaces: El Contrato
Una interface es como un contrato. Si un objeto dice ser un Usuario, DEBE cumplir el contrato.
interface Usuario {
name: string;
age: number;
isDeveloper: boolean;
}
const alice: Usuario = {
name: "Alice",
age: 39,
isDeveloper: true
}; // ✅ Cumple el contrato
const pepe: Usuario = {
name: "Pepe"
}; // ❌ Error: Faltan las propiedades 'age' e 'isDeveloper'interface Usuario {
name: string;
age: number;
isDeveloper: boolean;
}
const alice: Usuario = {
name: "Alice",
age: 39,
isDeveloper: true
}; // ✅ Cumple el contrato
const pepe: Usuario = {
name: "Pepe"
}; // ❌ Error: Faltan las propiedades 'age' e 'isDeveloper'Propiedades Opcionales (?)
A veces no tenemos todos los datos. Quizás el email es opcional.
Para eso usamos el signo de interrogación ? después del nombre de la propiedad.
interface Producto {
id: number;
nombre: string;
descripcion?: string; // 👈 Opcional (string | undefined)
}
const mesa: Producto = {
id: 1,
nombre: "Mesa de escritorio"
// No hace falta poner descripción
};interface Producto {
id: number;
nombre: string;
descripcion?: string; // 👈 Opcional (string | undefined)
}
const mesa: Producto = {
id: 1,
nombre: "Mesa de escritorio"
// No hace falta poner descripción
};Propiedades de Solo Lectura (readonly)
Si queremos asegurarnos de que una propiedad nunca cambie después de crear el objeto (como un ID), usemos readonly.
interface Configuracion {
readonly apiKey: string;
theme: "light" | "dark";
}
const config: Configuracion = {
apiKey: "xyz-123",
theme: "light"
};
config.theme = "dark"; // ✅ Puedes cambiarlo
config.apiKey = "abc-999"; // ❌ Error: Cannot assign to 'apiKey' because it is a read-only property.interface Configuracion {
readonly apiKey: string;
theme: "light" | "dark";
}
const config: Configuracion = {
apiKey: "xyz-123",
theme: "light"
};
config.theme = "dark"; // ✅ Puedes cambiarlo
config.apiKey = "abc-999"; // ❌ Error: Cannot assign to 'apiKey' because it is a read-only property.¿type vs interface?
Veremos gente usando type Usuario = { ... } en lugar de interface Usuario { ... }.
Para definir la forma de un objeto, ambos funcionan casi igual.
Regla de oro (por ahora):
- Usemos
interfacepara definir objetos que representan entidades (Usuario, Post, Producto).- Usemos
typepara Uniones (string | number), primitivos o tuplas.
En la Parte 8 profundizaremos en las diferencias técnicas, pero por ahora quedémonos con eso.
¡Intentémoslo!
Vamos a poner a prueba lo aprendido. Tenemos que definir una interfaz y crear un objeto específico para pasar la validación.
Requisitos del ejercicio:
- Definamos una interfaz llamada
Videojuegocon:titulo(string)anio(number) — Usamosaniopara evitar lañen código.plataforma(opcional, string)
- Creemos un objeto constante llamado
juegoFavoritoque implemente esa interfaz. - Los datos deben ser exactamente: “The Legend of Zelda”, año 1986.
¡Ey!
Probemos a activar el volumen del editor antes de darle al botón > Run cuando vayamos a resolver el ejercicio!
En la Parte 4, veremos qué pasa cuando tenemos muchos objetos iguales… es decir, Arrays.