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.
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 |
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);
}
id: number; void marca funciones sin retorno.available).discount(“100”, 20) no compila.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.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
}
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.
interface ApiResponse<T> {
data: T;
status: number;
}
const response: ApiResponse<Book> = { data: book, status: 200 };
<T> es un parámetro de tipo que se fija en cada uso: ApiResponse<Book> tiene data de tipo Book.Array<string> es lo mismo que string[].// 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
export publica y import consume; la extensión .js del import corresponde al archivo compilado de dist/.interface BookResponse {
id: number;
title: string;
authorName: string;
}
async function getBook(id: number): Promise<BookResponse> {
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.