cv.cm

Programación · Lenguajes de programación

Tutorial de TypeScript para principiantes

6 min de lectura

Respuesta corta

TypeScript es JavaScript con tipos estáticos. Añades anotaciones de tipo como let count: number = 0 y el compilador tsc las comprueba antes de convertir el código en JavaScript normal que se ejecuta en cualquier navegador o en Node.js. Las ideas clave son los tipos básicos, las interfaces y los alias de tipo para describir la forma de los objetos, los tipos unión con narrowing y los genéricos para código reutilizable. Los tipos se eliminan en tiempo de ejecución.

Abrir Formateador JSON

Qué es TypeScript y para qué se usa

TypeScript es un lenguaje de código abierto desarrollado por Microsoft y publicado por primera vez en 2012. Todo programa JavaScript válido es también TypeScript válido, así que puedes adoptarlo archivo por archivo. El verificador de tipos detecta errores como propiedades mal escritas o una comprobación de null que falta mientras escribes, y los editores usan los tipos para el autocompletado y para renombrar de forma segura. Se usa mucho en aplicaciones front-end grandes (Angular está escrito en TypeScript, y React, Vue y Svelte lo soportan bien), back ends con Node.js y bibliotecas.

Instalar y ejecutar Hello, world

Instala primero Node.js y luego el compilador en tu proyecto con npm. tsc compila archivos .ts a .js.

const message: string = "Hello, world";
console.log(message);
npm install --save-dev typescript
npx tsc --init          # creates tsconfig.json
npx tsc hello.ts        # writes hello.js
node hello.js
# Hello, world

Las versiones recientes de Node.js, Deno y Bun también pueden ejecutar archivos .ts directamente eliminando las anotaciones de tipo. No comprueban los tipos, así que ejecuta igualmente npx tsc --noEmit para encontrar errores de tipo.

Tipos básicos e inferencia de tipos

Rara vez necesitas escribir todos los tipos. Cuando inicializas una variable, TypeScript infiere su tipo: let n = 5 es un number. Anota los parámetros de las funciones y las API públicas.

TipoEjemploNotas
numberlet n: number = 3.5Enteros y decimales
stringlet s: string = "hi"Texto
booleanlet ok: boolean = trueverdadero o falso
Arraynumber[] o Array<number>Las dos formas significan lo mismo
Tupla[string, number]Longitud y posiciones fijas
unknownlet x: unknownCualquier valor; hay que comprobarlo antes de usarlo
anylet y: anyDesactiva la comprobación; evítalo
void / nevertipos de retorno de funcionesNo devuelve nada / nunca retorna
let count = 0;          // inferred as number
count = "ten";          // error: Type 'string' is not assignable to type 'number'
const names: string[] = ["Ann", "Bo"];
const pair: [string, number] = ["age", 31];

La segunda línea es un error de compilación intencionado, para ilustrar lo que informa el verificador.

Funciones, control de flujo y narrowing

El control de flujo (if, for, while, switch) es exactamente igual que en JavaScript. Lo que añade TypeScript es el narrowing (estrechamiento de tipos): tras una comprobación como typeof x === "string", el compilador conoce el tipo más específico dentro de esa rama.

function greet(name: string, greeting = "Hello"): string {
  return `${greeting}, ${name}!`;
}
function formatId(id: string | number): string {
  if (typeof id === "number") {
    return id.toFixed(0).padStart(6, "0"); // id is number here
  }
  return id.toUpperCase();                 // id is string here
}
console.log(greet("Lin"));    // Hello, Lin!
console.log(formatId(42));    // 000042
console.log(formatId("ab7")); // AB7

string | number es un tipo unión: el valor es uno de los tipos indicados. Los parámetros opcionales se escriben name?: string y su tipo incluye undefined.

Interfaces y alias de tipo

Describe la forma de los objetos con una interface o un alias type. TypeScript comprueba la estructura, no los nombres: cualquier objeto con las propiedades correctas encaja.

interface User {
  id: number;
  name: string;
  email?: string;          // optional
  readonly createdAt: Date;
}
type Role = "admin" | "editor" | "viewer"; // string literal union
function describe(user: User, role: Role): string {
  const contact = user.email ?? "no email";
  return `${user.name} (${role}, ${contact})`;
}
const ann: User = { id: 1, name: "Ann", createdAt: new Date() };
console.log(describe(ann, "editor")); // Ann (editor, no email)

Características distintivas: genéricos y uniones discriminadas

Los genéricos permiten que una función o un tipo funcione con muchos tipos manteniéndolos relacionados. Una unión discriminada es una unión de tipos de objeto que comparten un campo literal, de modo que un switch sobre ese campo estrecha el tipo y el compilador puede comprobar que se manejan todos los casos.

function first<T>(items: T[]): T | undefined {
  return items[0];
}
const n = first([10, 20]);   // n: number | undefined
const s = first(["a", "b"]); // s: string | undefined
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect"; width: number; height: number };
function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "rect":
      return shape.width * shape.height;
  }
}
console.log(n, s, area({ kind: "rect", width: 2, height: 3 })); // 10 a 6

Los tipos de utilidad integrados construyen tipos nuevos a partir de otros: Partial<User> hace opcionales todas las propiedades, Pick<User, "id" | "name"> conserva solo algunas y Record<string, number> describe un diccionario.

Manejo de errores

Los errores funcionan como en JavaScript, con throw y try/catch. Con la opción strict activada, el valor capturado tiene tipo unknown, porque se puede lanzar cualquier valor, así que compruébalo antes de usarlo.

function parseAge(text: string): number {
  const age = Number(text);
  if (!Number.isInteger(age) || age < 0) {
    throw new Error(`invalid age: ${text}`);
  }
  return age;
}
try {
  parseAge("abc");
} catch (err: unknown) {
  const message = err instanceof Error ? err.message : String(err);
  console.log(message); // invalid age: abc
}

Un programa completo pequeño: inventario tipado

interface Item {
  name: string;
  price: number;
  qty: number;
}
type Summary = { total: number; cheapest?: Item; outOfStock: string[] };
function summarize(items: Item[]): Summary {
  let total = 0;
  let cheapest: Item | undefined;
  const outOfStock: string[] = [];
  for (const item of items) {
    total += item.price * item.qty;
    if (item.qty === 0) outOfStock.push(item.name);
    if (!cheapest || item.price < cheapest.price) cheapest = item;
  }
  return { total, cheapest, outOfStock };
}
const result = summarize([
  { name: "pen", price: 1.5, qty: 10 },
  { name: "book", price: 12, qty: 2 },
  { name: "bag", price: 30, qty: 0 },
]);
console.log(result.total, result.cheapest?.name, result.outOfStock);
// 39 pen [ 'bag' ]

Prueba a cambiar qty: 10 por qty: "10": el compilador informa del error antes de que el código llegue a ejecutarse.

Errores comunes de principiantes

  • Usar any para silenciar errores. Es preferible unknown y estrecharlo.
  • Abusar de las aserciones de tipo con as, que le dicen al compilador que confíe en ti en lugar de comprobar.
  • Dejar strict desactivado en tsconfig.json. Actívalo en proyectos nuevos; habilita las comprobaciones de null.
  • Escribir tipos que el compilador ya puede inferir, lo que añade ruido sin dar seguridad.

Adónde ir después

Lee el TypeScript Handbook oficial y experimenta en el TypeScript Playground de typescriptlang.org, que muestra el JavaScript compilado y los errores lado a lado. Después aprende las opciones de tsconfig.json, los archivos de declaración de tipos para bibliotecas (paquetes @types/...) y TypeScript con el framework que elijas.

Preguntas frecuentes

¿TypeScript es un lenguaje distinto de JavaScript?

Es un superconjunto de JavaScript: añade sintaxis de tipos y un verificador, y luego compila a JavaScript normal. El comportamiento en tiempo de ejecución es el del JavaScript que genera.

¿Debo aprender JavaScript antes que TypeScript?

Aprende primero lo básico de JavaScript (variables, funciones, objetos, promesas), porque TypeScript no lo cambia. Después añade TypeScript; los tipos resultan más fáciles de aprender cuando ya conoces el comportamiento en tiempo de ejecución.

¿Cuál es la diferencia entre interface y type?

Ambos describen la forma de los objetos. Las interfaces pueden extenderse y fusionarse volviéndolas a declarar; los alias de tipo también pueden nombrar uniones, tuplas y otros tipos que no son objetos. Para formas de objeto sencillas sirven los dos.

¿TypeScript hace mi código más rápido?

No. Los tipos se eliminan durante la compilación, así que el resultado se ejecuta a la misma velocidad que JavaScript escrito a mano. El beneficio son menos errores y mejores herramientas.

Todos los tutoriales de programación