Maquetación Web Dinámica / TypeScript en la maquetación
Datos tipados: interfaces y render seguro
En el módulo 14 renderizaste una lista desde un array de objetos. Pero
nada te impedía escribir mal un campo (categoira), olvidar una propiedad
o meter un valor inválido — y solo lo descubrías cuando la tarjeta salía
rota. Con TypeScript defines la FORMA exacta de tus datos con una interfaz,
y a partir de ahí todo —crear los datos, renderizarlos, cambiarlos— queda
verificado. Es el superpoder más útil de TS para el maquetador.
La interfaz: el molde de tus datos
// la FORMA de una noticia: qué campos y de qué tipo
interface Noticia {
titulo: string;
categoria: "Ambiente" | "Ciudad" | "Cultura"; // tipo UNIÓN: solo estos 3 valores
resumen: string;
destacada?: boolean; // el '?' la hace OPCIONAL
}
// un array tipado: cada objeto DEBE cumplir la forma Noticia
const noticias: Noticia[] = [
{ titulo: "El páramo que fabrica agua", categoria: "Ambiente", resumen: "..." },
{ titulo: "Nueva ciclorruta", categoria: "Deportes", resumen: "..." },
// ❌ Error: "Deportes" no es asignable a "Ambiente" | "Ciudad" | "Cultura"
];Dos cosas potentes ya visibles: el tipo unión ("Ambiente" | "Ciudad" | "Cultura") restringe categoria a valores válidos —escribe "Deportes"
o "Ambiete" y TS lo rechaza, además de autocompletar los correctos—; y el
? marca campos opcionales. Si olvidas resumen, TS te avisa que
falta.
Render tipado: entra Noticia[], sale HTML
// la función declara qué recibe (Noticia[]) y qué devuelve (string)
function render(items: Noticia[]): string {
return items
.map((n) => "<article class='noticia'><span class='cat'>" + n.categoria +
"</span><h3>" + n.titulo + "</h3></article>")
.join("");
}
// dentro del map, 'n' es una Noticia: n.titulo autocompleta, n.titluo da errorAl tipar el parámetro como Noticia[], dentro del map cada n es una
Noticia: el editor te autocompleta n.titulo, n.categoria, y si
escribes n.titluo (typo) o n.precio (campo inexistente), rojo al
instante. La función también declara que DEVUELVE string: si por error
retornaras otra cosa, TS lo detecta.
El superpoder: cambia la forma, TS encuentra todo
Corriendo (el render, compilado)
<div class="app">
<input id="buscar" type="search" placeholder="Filtrar..." aria-label="Filtrar">
<div id="lista" class="lista"></div>
</div>body { font-family: system-ui; padding: 20px; background: #f8fafc; }
.app { max-width: 380px; display: grid; gap: 12px; }
#buscar { padding: 10px 12px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 15px; }
.lista { display: grid; gap: 8px; }
.noticia { background: white; border: 1px solid #e2e8f0; border-radius: 10px; padding: 12px 14px; }
.cat { font-size: 11px; font-weight: 700; text-transform: uppercase; color: #6d28d9; letter-spacing: 0.04em; }
.noticia h3 { margin: 4px 0 0; font-size: 15px; color: #1e293b; }// el JS compilado (los tipos Noticia y las anotaciones se borraron).
// en tu editor, 'noticias' estaba tipado como Noticia[] y render como (Noticia[]) => string.
const noticias = [
{ titulo: "El paramo que fabrica agua", categoria: "Ambiente", resumen: "" },
{ titulo: "Nueva ciclorruta al norte", categoria: "Ciudad", resumen: "" },
{ titulo: "Festival de cine en Bogota", categoria: "Cultura", resumen: "" },
];
const lista = document.querySelector("#lista");
const buscar = document.querySelector("#buscar");
function render(items) {
lista.innerHTML = items.map((n) =>
"<article class='noticia'><span class='cat'>" + n.categoria +
"</span><h3>" + n.titulo + "</h3></article>"
).join("");
}
if (lista && buscar) {
render(noticias);
buscar.addEventListener("input", (event) => {
const q = event.target.value.toLowerCase();
render(noticias.filter((n) => n.titulo.toLowerCase().includes(q)));
});
}Defines interface Producto con un campo precio: number. Más adelante decides que precio debe ser un objeto { valor: number, moneda: string }. ¿Qué te da TypeScript al hacer ese cambio?
Mini-reto
Convierte las noticias de "El Observador" en datos tipados: define
interface Noticia con titulo, categoria (unión de tus secciones),
resumen y un destacada? opcional, crea el array Noticia[] y una
función render(items: Noticia[]): string. Luego prueba el superpoder:
renombra titulo a titular en la interfaz y observa cuántos sitios se
encienden en rojo pidiéndote el cambio. Ese mapa es lo que hace grande a
TypeScript.
Qué sigue
Tienes todo el arsenal: elementos, eventos, patrones y datos, tipados. El reto del módulo lo reúne: migrar el proyecto completo del módulo 14 —la página viva con reveals, navbar y modal— a TypeScript estricto, sin un solo error del compilador. Tu graduación como maquetador con red de seguridad.