====== 06 - TypeScript ======
**TypeScript** es un superconjunto tipado de **JavaScript** (tema 04): añade **tipos estáticos** que el compilador comprueba y que **no existen en la ejecución**. Se compila con **tsc**, y el JavaScript resultante es lo que ejecutan el navegador y **Node**. La instalación del proyecto con npm se explica en el tema 05.
===== 1. Compilación =====
npm install --save-dev typescript # dependencia de desarrollo (tema 05)
npx tsc src/main.ts # compila un fichero suelto
npx tsc # compila según tsconfig.json
npx tsc --watch # recompila al guardar
node dist/main.js # ejecuta el resultado compilado
El ''tsconfig.json'' configura la compilación; ''npx tsc --init'' genera uno de partida:
{
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"outDir": "dist",
"rootDir": "src",
"strict": true
}
}
^ Opción ^ Función ^
| ''target'' | versión de JavaScript que genera el compilador |
| ''module'' | sistema de módulos del resultado (''import''/''export'') |
| ''outDir'' / ''rootDir'' | carpeta de salida (''dist'') y de origen (''src'') |
| ''strict'' | exige disciplina de tipos; configuración recomendada |
===== 2. Anotaciones e inferencia =====
const id: number = 42;
const title: string = "Código limpio";
const available = true; // boolean: lo deduce el compilador
const tags: string[] = ["programming", "craft"];
const pair: [string, number] = ["total", 3]; // tupla: tipos por posición
function discount(price: number, percent: number): number {
return price * (1 - percent / 100);
}
function announce(message: string): void { // no devuelve nada
console.log(message);
}
* La anotación se escribe tras el nombre: ''id: number''; ''void'' marca funciones sin retorno.
* Cuando el valor es evidente, el compilador deduce el tipo sin anotarlo (''available'').
* No hay conversión implícita: ''discount("100", 20)'' no compila.
===== 3. Interfaces =====
Una interfaz describe la **forma** de los datos, no su comportamiento:
interface Book {
id: number;
title: string;
available: boolean;
authorId?: number; // opcional: puede faltar
readonly createdAt: Date; // no modificable tras crearlo
}
const book: Book = {
id: 1,
title: "Código limpio",
available: true,
createdAt: new Date(),
};
* ''?'' marca la propiedad que puede faltar; el compilador obliga a contemplar su ausencia al usarla.
* ''readonly'' impide modificar la propiedad desde el exterior tras crear el objeto.
===== 4. Uniones, literales y narrowing =====
Los **tipos literales** restringen un valor a opciones concretas:
type Genre = "novela" | "ensayo" | "teatro";
type OrderStatus = "PENDING" | "CONFIRMED" | "CANCELLED";
function canCancel(status: OrderStatus): boolean {
return status === "PENDING";
}
canCancel("SENT"); // error de compilación: el literal no está en la unión
Una unión también puede mezclar tipos; en cada rama el compilador **acota** el tipo disponible:
function describe(value: string | number): string {
if (typeof value === "string") return value;
return `id ${value}`; // aquí, value es number
}
===== 5. any y unknown =====
let data: any = JSON.parse(text); // evítalo: desactiva la comprobación
let payload: unknown = JSON.parse(text); // admite cualquier valor,
// pero exige comprobar el tipo antes de usarlo
if (typeof payload === "string") {
console.log(payload.toUpperCase()); // ok: ya es string
}
''any'' contagia la ausencia de tipos a todo lo que toca; ''unknown'' obliga a comprobar el tipo antes de operar. Se usa ''unknown'' cuando no se conoce el contenido y tipos concretos en cuanto se pueda.
===== 6. Genéricos =====
interface ApiResponse {
data: T;
status: number;
}
const response: ApiResponse = { data: book, status: 200 };
* '''' es un parámetro de tipo que se fija en cada uso: ''ApiResponse'' tiene ''data'' de tipo ''Book''.
* Sirve para un mismo envoltorio con distintos contenidos; ''Array'' es lo mismo que ''string[]''.
===== 7. Clases y módulos =====
// src/price-calculator.ts
export class PriceCalculator {
discount(price: number, percent: number): number {
return price * (1 - percent / 100);
}
}
// src/main.ts
import { PriceCalculator } from "./price-calculator.js";
const calculator = new PriceCalculator();
console.log(calculator.discount(100, 20)); // 80
* La POO es la ya estudiada en Programación; TypeScript añade los tipos a campos, parámetros y retorno.
* ''export'' publica y ''import'' consume; la extensión ''.js'' del import corresponde al **archivo compilado** de ''dist/''.
===== 8. Tipos y datos de una API =====
interface BookResponse {
id: number;
title: string;
authorName: string;
}
async function getBook(id: number): Promise {
const response = await fetch(`/api/books/${id}`);
return response.json();
}
* ''fetch'' y ''async''/''await'' se explican en el tema 07; el tipo describe el JSON que entregará la API.
* Si la API cambia su JSON, el compilador avisa de todos los puntos del cliente que necesitan adaptarse.
Los tipos no existen en la ejecución: no viajan en el JSON ni validan lo que llega. Su valor está en detectar errores antes de ejecutar y en documentar la forma de los datos que viajan entre cliente y API.