Apariencia
📙 Clase 12 — TypeScript compilado y ejecutado en el navegador
TypeScript · 2026-08-06 · Carpeta:
02-Ejercicios/Web⬅️ Volver al índice de clases
🎯 Qué aprendí
- Por qué el navegador no entiende
.tsdirectamente y siempre hay que compilar a.jsantes de usarlo en un HTML. - Cómo conectar un
index.htmlcon el JavaScript compilado usando<script src="...">. - Cómo previsualizar el HTML en vivo con Live Server o Live Preview (extensiones de VS Code) en vez de abrir el archivo a mano.
- Cómo confirmar que el código llegó al navegador revisando la consola de DevTools (
F12→ pestaña Console). - Tres gotchas reales que comprobé en el navegador: olvidar recompilar deja el sitio desactualizado, el orden de los
<script>importa sin módulos, y usarimport/export(de la Clase 11) directo en un<script>normal truena si no le agregastype="module".
📚 Definiciones clave
| Término | Qué es | Ejemplo de esta clase |
|---|---|---|
tsc archivo.ts | Compila TypeScript a JavaScript — el navegador solo lee lo que sale de aquí | tsc main.ts → genera main.js |
<script src="main.js"> | Le dice al HTML qué JavaScript cargar y ejecutar | index.html apunta a main.js, no a main.ts |
| Live Server / Live Preview | Extensión de VS Code que sirve tu HTML en una URL localhost con recarga automática | Botón Go Live / icono Show Preview |
| DevTools Console | Panel del navegador donde aparecen tus console.log() | F12 → Console |
📖 PARTE TEÓRICA
🌐 1. Por qué necesito compilar TypeScript antes de usarlo en HTML
El navegador no entiende TypeScript de forma nativa — solo lee JavaScript. Cualquier archivo .ts necesita pasar por el compilador antes de poder invocarse desde un HTML.
La lógica es simple: TypeScript existe para mejorar el tipado dentro de JavaScript, pero JavaScript es el lenguaje que en verdad corre en el navegador. Por eso el flujo siempre es el mismo: escribir en TypeScript → compilar → dejar que el HTML cargue el JavaScript resultante.
🧪 Entrevista: ¿Por qué el navegador no puede leer TypeScript directamente? Porque TypeScript es un superset de JavaScript que añade tipado estático — es una capa que solo existe en tiempo de compilación. Los navegadores únicamente ejecutan JavaScript, así que hace falta
tscpara generar el.jsque el HTML sí puede invocar.
🗂️ 2. Estructura del proyecto web: index.html + main.ts
Un proyecto web mínimo con TypeScript necesita dos archivos que trabajan en conjunto:
index.html— un HTML genérico que invoca el script compilado con<script src="main.js"></script>.main.ts— el archivo TypeScript con la lógica (en el ejemplo, unconsole.log("Hola desde mi explorador"), la variante web del clásico hola mundo).
html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script src="main.js"></script>
</head>
<body>
<h1 class="title">Mi curso de Typescript en Platzi</h1>
<label for="message">Escribe algo:</label>
<input type="text" id="message" placeholder="Mensaje del usuario" />
</body>
</html>typescript
// main.ts
console.log("Hola desde mi explorador");💡 Fíjate en el detalle: el HTML llama a
main.js, no amain.ts. Esa es la pista de que hace falta compilar antes de abrir el sitio — si el HTML pidieramain.tsdirectamente, el navegador simplemente no sabría qué hacer con él.
⚙️ 3. Compilar main.ts a main.js
Desde la terminal, parado en la carpeta del proyecto:
bash
cd 02-Ejercicios/Web
tsc main.tsSi corres ls después, aparece main.js junto al original — en VS Code también se ve en el árbol de archivos. Ese archivo generado es el que el HTML va a leer sin problemas.
👀 4. Previsualizar el HTML directamente desde VS Code
Para ver el resultado en el navegador sin abrir el archivo manualmente (doble clic), conviene instalar una extensión que levante un servidor local. Dos opciones:
| Extensión | Autor | Cómo se activa |
|---|---|---|
| Live Server | Ritwick Dey (+60M descargas) | Botón Go Live en la barra inferior de VS Code |
| Live Preview | Microsoft | Icono Show Preview dentro del editor al abrir un .html |
💡 ¿Qué hace Live Server? Levanta un servidor local que sirve tus archivos HTML en una URL tipo
http://localhost, con recarga automática cuando guardas cambios. Es la forma más rápida de previsualizar un proyecto web estático — el mismo principio que usa este propio sitio de apuntes connpm run docs:dev(VitePress), solo que aquí es para HTML plano sin framework.
🔍 5. Verificar que TypeScript está funcionando en el navegador
Con la previsualización abierta, el siguiente paso es revisar la consola del explorador — ahí se confirma que el console.log escrito en TypeScript llegó hasta el navegador.
- Dentro de Live Preview: abres el panel de herramientas de desarrollo desde el menú de la extensión y entras a la pestaña Console.
- Fuera de VS Code: copias la URL de
localhost, la pegas en tu navegador (Chrome, Edge, el que sea) y presionasF12para abrir DevTools → pestaña Console.
En cualquiera de los dos casos, el resultado es idéntico: el mensaje aparece en consola.
Verificado en este equipo sirviendo 02-Ejercicios/Web/index.html en un localhost real y leyendo la consola del navegador:
Hola desde mi explorador🧭 6. La cadena completa: de .ts a la pantalla
main.ts --tsc--> main.js <--<script src>-- index.html --navegador--> Console (F12)
(tipos) (JS puro) (lo invoca) (lo ejecuta) (lo muestro)Es el mismo console.log que antes corrías con node en la terminal (Clase 1), solo que ahora vive en un sitio web real: escribes en main.ts, compilas con tsc y se genera main.js, el index.html invoca ese main.js con la etiqueta <script>, y el navegador lo ejecuta y muestra el resultado en consola. Así es como TypeScript hereda funcionalidad a JavaScript, y JavaScript la representa gracias al HTML.
💻 PARTE PRÁCTICA
Archivos trabajados: 02-Ejercicios/Web/index.html y 02-Ejercicios/Web/main.ts
typescript
// main.ts
console.log("Hola desde mi explorador");bash
cd 02-Ejercicios/Web
tsc main.tsSalida real verificada — servido en localhost real y confirmado en la consola del navegador (no solo compilado, también ejecutado en Chrome de verdad):
$ tsc main.ts
$ ls
index.html main.js main.tsTodo verificado y corriendo. ✅
🏋️ EJERCICIOS CON SOLUCIÓN
Ejercicio 1 — Cambiar el mensaje y recompilar
Cambia el texto del console.log en main.ts por uno propio, recompílalo y confirma en la consola del navegador (con Live Server o F12) que el mensaje nuevo aparece.
💡 ¿Sabías que…? — el HTML nunca ve tu `.ts`
El HTML solo conoce el archivo que declaraste en <script src="..."> — en este caso main.js. Cambiar main.ts no actualiza automáticamente lo que ve el navegador: hace falta recompilar (tsc main.ts) para que el .js se regenere con el nuevo texto. Ejemplo de referencia:
typescript
// antes
console.log("Primera versión");
// después de editar y recompilar
console.log("Segunda versión, ya recompilada");Ver solución
typescript
// main.ts
console.log("Hola, este es mi propio mensaje en el navegador");bash
tsc main.tsConsola del navegador tras recargar:
Hola, este es mi propio mensaje en el navegadorEjercicio 2 — Variable tipada + template string
Declara una constante nombre: string y muéstrala en consola con un template string (repaso de la Clase 1).
💡 ¿Sabías que…? — el tipado no cambia el JS generado
const nombre: string = "algo" compila a const nombre = "algo"; — la anotación de tipo : string desaparece por completo en el .js. Sirve solo en tiempo de compilación, para que tsc te avise si intentas asignarle un número por error. Ejemplo de referencia:
typescript
const ciudad: string = "Lima";
console.log(`Vivo en ${ciudad}`);Ver solución
Archivo real: 02-Ejercicios/Web/variable-tipada.ts
typescript
const nombre: string = "Styp";
console.log(`Hola, ${nombre} desde TypeScript`);Verificado con tsc variable-tipada.ts + ejecución real:
Hola, Styp desde TypeScriptEjercicio 3 — Loguear varios tipos en un solo mensaje
Declara edad: number y activo: boolean, y muéstralos juntos en un solo console.log con template string.
💡 ¿Sabías que…? — el template string convierte todo a texto
Dentro de ${...}, un template string llama internamente a .toString() sobre cualquier valor — por eso number y boolean se insertan sin problema junto a texto, aunque sean tipos distintos. Ejemplo de referencia:
typescript
const precio: number = 49.9;
const disponible: boolean = false;
console.log(`Precio: ${precio}, Disponible: ${disponible}`);Ver solución
Archivo real: 02-Ejercicios/Web/tipos-multiples.ts
typescript
const edad: number = 25;
const activo: boolean = true;
console.log(`Edad: ${edad}, Activo: ${activo}`);Verificado con tsc tipos-multiples.ts + ejecución real:
Edad: 25, Activo: trueEjercicio 4 — Leer el valor del <input> del HTML
El index.html de la práctica ya trae <input type="text" id="message" />. Escribe un .ts que lo lea con document.getElementById y lo muestre en consola.
💡 ¿Sabías que…? — el DOM necesita un cast explícito
document.getElementById devuelve el tipo genérico HTMLElement | null — TypeScript no sabe de antemano que ese elemento es un <input>, así que no te deja leer .value directamente sin avisarte. Se resuelve con as HTMLInputElement (un type assertion: "confío en que este elemento es un input"). Ejemplo de referencia:
typescript
const campo = document.getElementById("buscador") as HTMLInputElement;
console.log(campo.value);Ver solución
Archivos reales: 02-Ejercicios/Web/dom-input.html + dom-input.ts
typescript
// dom-input.ts
const input = document.getElementById("message") as HTMLInputElement;
console.log(input.value);Verificado en Chrome real, sirviendo el HTML en un localhost (input con value="Hola Mundo" por defecto):
Hola Mundo⚠️ Si el
<script>va en el<head>sindefer, el JS corre antes de que el<input>exista en el DOM ygetElementByIddevuelvenull— truena al leer.value. Por eso este archivo agregadeferal<script src="dom-input.js" defer>.
Ejercicio 5 — Cambiar el <h1> desde TypeScript
Usa document.querySelector para tomar el <h1 class="title"> del HTML y cambiar su texto con .textContent.
💡 ¿Sabías que…? — `querySelector` usa sintaxis CSS
document.querySelector acepta cualquier selector CSS (.clase, #id, tag), a diferencia de getElementById que solo busca por id. Igual que en el ejercicio 4, hace falta un cast porque TypeScript no sabe qué tipo exacto de elemento vas a encontrar. Ejemplo de referencia:
typescript
const parrafo = document.querySelector("p.descripcion") as HTMLParagraphElement;
parrafo.textContent = "Texto actualizado";Ver solución
Archivos reales: 02-Ejercicios/Web/titulo-dinamico.html + titulo-dinamico.ts
typescript
// titulo-dinamico.ts
const titulo = document.querySelector(".title") as HTMLHeadingElement;
titulo.textContent = "Título cambiado desde TypeScript";Verificado en Chrome real — el <h1> cambia de "Mi curso de Typescript en Platzi" a:
Título cambiado desde TypeScriptEjercicio 6 — Función tipada que usa el valor del input
Crea function saludar(nombre: string): string (repaso de la Clase 4) que arme un saludo, y úsala con el valor del <input> para loguear el resultado.
💡 ¿Sabías que…? — una función tipada no sabe de dónde viene el dato
saludar(nombre: string) no le importa si nombre viene de un input, una constante o un array — solo exige que sea string. Por eso combinar DOM + funciones tipadas es tan directo: lees el .value (que ya es string), y se lo pasas tal cual. Ejemplo de referencia:
typescript
function despedir(nombre: string): string {
return `Adiós, ${nombre}, vuelve pronto`;
}
console.log(despedir("visitante"));Ver solución
Archivos reales: 02-Ejercicios/Web/saludo-funcion.html + saludo-funcion.ts
typescript
// saludo-funcion.ts
function saludar(nombre: string): string {
return `¡Hola, ${nombre}! Bienvenido a TypeScript en el navegador`;
}
const input = document.getElementById("message") as HTMLInputElement;
console.log(saludar(input.value));Verificado en Chrome real (input con value="Styp"):
¡Hola, Styp! Bienvenido a TypeScript en el navegadorEjercicio 7 — Forzar el desfase de olvidar recompilar
Antes de correrlo: si editas main.ts pero no vuelves a correr tsc, y recargas el navegador, ¿qué mensaje esperas ver? Anticipa tu respuesta y compruébalo.
💡 ¿Sabías que…? — el navegador nunca lee `.ts`, ni por accidente
El <script> apunta siempre al .js compilado — el navegador no tiene forma de saber que el .ts cambió, porque ni siquiera lo carga. Mientras no corras tsc de nuevo, vas a seguir viendo la versión vieja del .js, sin importar cuántas veces recargues la página o guardes el .ts. Es la razón por la que Live Server con recarga automática NO reemplaza a recompilar: recarga el HTML, no regenera el JavaScript.
Ver solución
Verificado en terminal + Chrome real, paso a paso:
bash
echo 'console.log("Versión A");' > demo.ts
tsc demo.ts # genera demo.js con "Versión A"
# ... abres demo.html en el navegador → consola muestra "Versión A"
echo 'console.log("Versión B - cambiada");' > demo.ts # editas el .ts, SIN recompilar
# ... recargas el navegador → consola SIGUE mostrando "Versión A" (el .js no cambió)
tsc demo.ts # ahora sí recompilas
# ... recargas de nuevo → consola muestra "Versión B - cambiada"Versión A ← tras editar el .ts SIN recompilar, sigue igual
Versión B - cambiada ← recién ahora, tras `tsc demo.ts`⚠️ Este es el bug más común al empezar con TS en el navegador: "hice el cambio y no se ve nada" casi siempre significa te faltó recompilar.
Ejercicio 8 — Orden de <script> sin módulos
Crea uno.ts con const mensajeGlobal = "..." y dos.ts con console.log(mensajeGlobal) (ninguno usa export/import). Colócalos en el HTML en ambos órdenes y observa qué pasa en cada caso.
💡 ¿Sabías que…? — sin módulos, los scripts comparten un solo scope global
Sin export/import (visto en la Clase 11), varios <script> en un mismo HTML se ejecutan en el orden en que aparecen, y todos comparten el mismo scope global — por eso un script posterior puede usar una variable declarada en uno anterior. Pero si el orden se invierte, la variable todavía no existe cuando el segundo script corre. Ejemplo de referencia:
typescript
// base.ts
const version = "2.0";typescript
// app.ts
console.log(`Versión: ${version}`); // solo funciona si base.js carga ANTESVer solución
typescript
// uno.ts
const mensajeGlobal = "Vengo del primer script";typescript
// dos.ts
console.log(mensajeGlobal);html
<!-- orden CORRECTO -->
<script src="uno.js"></script>
<script src="dos.js"></script>html
<!-- orden INCORRECTO -->
<script src="dos.js"></script>
<script src="uno.js"></script>Verificado en Chrome real, ambos casos:
-- orden correcto (uno.js, luego dos.js) --
Vengo del primer script
-- orden incorrecto (dos.js, luego uno.js) --
Uncaught ReferenceError: mensajeGlobal is not defined💡 Este es exactamente el problema que los módulos (
export/import, Clase 11) resuelven de raíz: cada archivo declara explícitamente qué necesita de dónde, en vez de depender del orden físico de las etiquetas<script>.
Ejercicio 9 — Intentar usar import/export sin type="module"
Toma un archivo compilado que use import/export (como los de la Clase 11) y cárgalo con un <script src="..."> normal, sin type="module". Anticipa el error y verifícalo.
💡 ¿Sabías que…? — `type="module"` no es opcional para ES Modules en el navegador
Un <script> normal se ejecuta como script clásico: el navegador espera JavaScript "plano", sin import/export de nivel superior. Para que el navegador entienda esa sintaxis (los ES Modules nativos), el <script> necesita el atributo type="module" — sin él, la etiqueta import es simplemente sintaxis inválida para ese contexto. Ejemplo de referencia:
html
<!-- así SÍ entiende el import -->
<script src="app.js" type="module"></script>Ver solución
typescript
// config-modulo.ts
export const version = "1.0.0";typescript
// modulo-error.ts
import { version } from "./config-modulo.js";
console.log(version);html
<!-- sin type="module": esto truena -->
<script src="modulo-error.js" defer></script>Verificado en Chrome real:
Uncaught SyntaxError: Cannot use import statement outside a moduleAgregando type="module" al <script> (<script src="modulo-error.js" type="module">), el mismo archivo corre sin problema:
1.0.0⚠️ En proyectos reales casi nunca se agrega
type="module"a mano en varios<script>sueltos — se usa un bundler (Vite, Webpack, esbuild…) que empaqueta todos los módulos en un solo archivo optimizado. Pero entender por qué truena sintype="module"ayuda a leer el error el día que aparezca.
Ejercicio 10 — Integrador: mini formulario con validación
Arma un HTML con <input id="message">, un <button id="enviar"> y un <p id="resultado">. Al hacer clic en el botón, valida que el input no esté vacío y muestra el resultado tanto en consola como en el <p>.
💡 ¿Sabías que…? — `addEventListener` conecta TypeScript con la interacción del usuario
Todo lo visto hasta acá (compilar, leer el DOM, funciones tipadas) se combina aquí con addEventListener("click", ...): en vez de correr el código una sola vez al cargar la página, lo dejas esperando a que el usuario interactúe. Ejemplo de referencia:
typescript
const boton = document.getElementById("calcular") as HTMLButtonElement;
boton.addEventListener("click", () => {
console.log("Se hizo clic");
});Ver solución
Archivos reales: 02-Ejercicios/Web/formulario.html + formulario.ts
typescript
// formulario.ts
function validarMensaje(valor: string): string {
if (valor.trim() === "") {
return "⚠️ El mensaje no puede estar vacío";
}
return `✅ Mensaje recibido: ${valor}`;
}
const input = document.getElementById("message") as HTMLInputElement;
const boton = document.getElementById("enviar") as HTMLButtonElement;
const resultado = document.getElementById("resultado") as HTMLParagraphElement;
boton.addEventListener("click", () => {
const mensaje = validarMensaje(input.value);
console.log(mensaje);
resultado.textContent = mensaje;
});Verificado en Chrome real, ambos casos (clic con texto y clic con input vacío):
✅ Mensaje recibido: Styp
⚠️ El mensaje no puede estar vacío💡 Este ejercicio junta todo el recorrido de la clase:
tscpara compilar, DOM para leer/escribir, funciones tipadas para la lógica, y eventos para responder al usuario — el mismo patrón detrás de cualquier formulario web real.
❓ Preguntas y respuestas (autoevaluación)
1. ¿Por qué el navegador no puede ejecutar un archivo .ts directamente?
Porque los navegadores solo entienden JavaScript. TypeScript es un superset que añade tipado estático, pero esa capa solo existe en tiempo de compilación — hay que convertirlo a
.jscontscantes de que un HTML pueda invocarlo.
2. En el index.html de esta clase, ¿por qué el <script src> apunta a main.js y no a main.ts?
Porque el navegador solo puede cargar JavaScript.
main.jses el archivo generado portsc main.ts— el HTML nunca ve ni necesita el.tsoriginal.
3. ¿Qué comando compila main.ts a main.js?
tsc main.ts, corrido desde la carpeta donde está el archivo.
4. ¿Qué hace una extensión como Live Server?
Levanta un servidor local que sirve tus archivos HTML en una URL
http://localhost, con recarga automática al guardar cambios — evita tener que abrir el HTML a mano con doble clic.
5. ¿Dónde reviso si mi console.log de TypeScript llegó al navegador?
En la consola de DevTools:
F12(o el menú de Live Preview) → pestaña Console.
6. Si edito main.ts pero no vuelvo a correr tsc, ¿qué va a mostrar el navegador al recargar?
El mensaje viejo. El
<script>apunta al.jscompilado, no al.ts— sin recompilar, el.jsno cambia, sin importar cuántas veces recargues la página.
7. ¿Por qué document.getElementById("message") necesita un as HTMLInputElement para poder leer .value?
Porque
getElementByIddevuelve el tipo genéricoHTMLElement | null— TypeScript no sabe de antemano qué tipo específico de elemento es. Elases un type assertion que le dice al compilador "confío en que esto es un<input>".
8. Si tengo dos <script> sin export/import, y el segundo usa una variable declarada en el primero, ¿qué pasa si invierto el orden de las etiquetas?
ReferenceError: <variable> is not defined. Sin módulos, los scripts comparten un solo scope global y se ejecutan en el orden físico en que aparecen en el HTML — si el que usa la variable carga antes que el que la declara, todavía no existe.
9. ¿Qué error da el navegador si cargo un .js compilado con import/export en un <script> normal, sin type="module"?
Uncaught SyntaxError: Cannot use import statement outside a module. Un<script>normal se ejecuta como script clásico, que no entiende la sintaxis de ES Modules — hace falta agregartype="module"a la etiqueta para que funcione.
10. ¿Cuál es la cadena completa desde que escribo código hasta que lo veo en el navegador?
main.ts(escribo con tipos) →tsc main.ts(compilo) →main.js(JS puro) →index.htmllo invoca con<script src="main.js">→ el navegador lo ejecuta → el resultado aparece en la consola de DevTools (F12).
📎 Apuntes relacionados
- Clase 1: variables base y compilar con
tsc/node - Clase 4: funciones tipadas
- Clase 11:
export/import, y por qué el orden de compilación importa - Conceptos
- Comandos
➡️ Siguiente
Utility types — Partial, Pick, Omit, Record… transformar tipos existentes sin reescribirlos.