Introducción a TypeScript

Básico
TypeScript
TypeScript
Actualizado: 04/05/2026

Diagrama: tutorial-typescript-introduccion

Qué es TypeScript

TypeScript es un lenguaje de programación de código abierto desarrollado y mantenido por Microsoft. Se define como un superconjunto de JavaScript, lo que significa que todo código JavaScript válido es también código TypeScript válido. La aportación fundamental de TypeScript es un sistema de tipos estático que permite describir la forma de los datos y detectar errores antes de ejecutar el programa.

TypeScript añade tipos a JavaScript. El compilador verifica esos tipos durante el desarrollo y los elimina al generar el JavaScript final.

El resultado de compilar un archivo .ts es un archivo .js convencional que puede ejecutarse en cualquier entorno compatible con JavaScript: navegadores, Node.js, Deno, Bun o cualquier otro runtime. La información de tipos solo existe durante la fase de desarrollo y compilación.

function sumar(a: number, b: number): number {
  return a + b;
}

const resultado = sumar(3, 5);
console.log(resultado);

En este ejemplo, las anotaciones : number indican al compilador que a y b deben ser números y que la función devuelve un número. Si alguien intenta pasar un argumento de tipo incorrecto, TypeScript señala el error antes de ejecutar el código.

// Error de compilación: Argument of type 'string' is not assignable to parameter of type 'number'
const mal = sumar("tres", 5);

El proceso de compilación

TypeScript no se ejecuta directamente. El compilador tsc (TypeScript Compiler) lee los archivos .ts, verifica los tipos y genera archivos .js equivalentes. Durante este proceso, todas las anotaciones de tipo desaparecen del código resultante.

// Código TypeScript (saludo.ts)
function saludar(nombre: string): string {
  return `Hola, ${nombre}`;
}

const mensaje: string = saludar("Ana");
console.log(mensaje);

Tras la compilación, el JavaScript generado es:

// Código JavaScript generado (saludo.js)
function saludar(nombre) {
  return `Hola, ${nombre}`;
}

const mensaje = saludar("Ana");
console.log(mensaje);

Las anotaciones : string han desaparecido. El JavaScript resultante es código limpio que cualquier motor puede interpretar. Este flujo de trabajo tiene una consecuencia importante: los tipos de TypeScript no existen en tiempo de ejecución. No hay comprobaciones de tipo cuando el programa se está ejecutando, solo durante la compilación.

Compatibilidad total con JavaScript

Dado que TypeScript es un superconjunto, cualquier archivo .js puede renombrarse a .ts y el compilador lo aceptará. Esto permite una adopción gradual en proyectos existentes. No es necesario reescribir todo el código de golpe; se pueden ir anadiendo tipos archivo por archivo, función por función.

// Este código JavaScript puro es también TypeScript válido
function multiplicar(a, b) {
  return a * b;
}

const total = multiplicar(4, 7);
console.log(total);

TypeScript inferira los tipos donde pueda y marcara como any implícito lo que no pueda deducir, dependiendo de la configuración de strictness del proyecto.

Tipado estructural

TypeScript implementa un sistema de tipado estructural, también conocido como "duck typing" en el ámbito de los tipos. Esto significa que el compilador no compara los nombres de los tipos ni exige herencia explícita. En su lugar, compara la forma de los datos: si un objeto tiene las propiedades esperadas con los tipos correctos, es compatible, independientemente de como se haya declarado.

Si un objeto tiene la forma que el tipo espera, TypeScript lo acepta. No importa el nombre del tipo ni la cadena de herencia.

type Punto = {
  x: number;
  y: number;
};

function distanciaAlOrigen(punto: Punto): number {
  return Math.sqrt(punto.x ** 2 + punto.y ** 2);
}

const miObjeto = { x: 3, y: 4, nombre: "A" };
const distancia = distanciaAlOrigen(miObjeto);
console.log(distancia);

La variable miObjeto no fue declarada como tipo Punto, pero tiene las propiedades x e y con tipo number. Eso es suficiente para que TypeScript acepte la llamada. La propiedad adicional nombre no causa problemas porque el objeto cumple el contrato mínimo que exige Punto.

Contraste con tipado nominal

En lenguajes con tipado nominal como Java o C#, dos tipos con la misma estructura pero nombres diferentes serian incompatibles. En TypeScript, lo que importa es la estructura:

type Rectangulo = {
  ancho: number;
  alto: number;
};

type Pantalla = {
  ancho: number;
  alto: number;
};

function calcularArea(rect: Rectangulo): number {
  return rect.ancho * rect.alto;
}

const miPantalla: Pantalla = { ancho: 1920, alto: 1080 };
const area = calcularArea(miPantalla);
console.log(area);

Aunque miPantalla es de tipo Pantalla y la función espera Rectángulo, TypeScript acepta la llamada porque ambos tipos tienen exactamente la misma estructura. Esta filosofía hace que el sistema de tipos sea flexible y se adapte bien al estilo dinámico de JavaScript.

Verificación en objetos literales

Hay una excepción importante al tipado estructural. Cuando se pasa un objeto literal directamente a una función o variable tipada, TypeScript aplica la verificación de propiedades excedentes (excess property checking):

type Configuración = {
  host: string;
  puerto: number;
};

// Error: Object literal may only specify known properties, and 'protocolo' does not exist in type 'Configuración'
const config: Configuración = {
  host: "localhost",
  puerto: 3000,
  protocolo: "https"
};

Esta verificación adicional solo se aplica a objetos literales y sirve para detectar errores tipograficos o propiedades innecesarias en el punto de creación.

Ventajas del sistema de tipos

El sistema de tipos de TypeScript proporciona beneficios concretos que transforman la experiencia de desarrollo. Estos beneficios son más evidentes a medida que el tamano del proyecto y del equipo crece.

Detección temprana de errores

TypeScript identifica errores frecuentes antes de ejecutar el código. Errores tipograficos en nombres de propiedades, operaciones con tipos incompatibles y llamadas a funciones con argumentos incorrectos se detectan en el momento de escribir el código:

type Usuario = {
  nombre: string;
  email: string;
  edad: number;
};

function enviarCorreo(usuario: Usuario): void {
  // Error detectado: Property 'correo' does not exist on type 'Usuario'. Did you mean 'email'?
  console.log(usuario.correo);
}

El compilador no solo detecta el error sino que sugiere la propiedad correcta. Este tipo de retroalimentación inmediata reduce drasticamente el tiempo dedicado a depurar problemas triviales.

Autocompletado inteligente

El sistema de tipos alimenta directamente al autocompletado del editor. Cuando TypeScript conoce el tipo de una variable, el editor puede sugerir todas las propiedades y métodos disponibles con información precisa sobre sus firmas:

type Producto = {
  id: string;
  nombre: string;
  precio: number;
  stock: number;
};

function formatearProducto(producto: Producto): string {
  // Al escribir "producto.", el editor sugiere: id, nombre, precio, stock
  return `${producto.nombre} - ${producto.precio} EUR (${producto.stock} unidades)`;
}

const catalogo: Producto[] = [
  { id: "p1", nombre: "Teclado", precio: 49.99, stock: 25 },
  { id: "p2", nombre: "Raton", precio: 29.99, stock: 50 }
];

// Al escribir "catalogo.", el editor sugiere todos los métodos de Array
const nombres = catalogo.map(p => p.nombre);
console.log(nombres);

Este autocompletado elimina la necesidad de consultar documentación constantemente y reduce los errores al escribir código.

Refactorización segura

Cuando se modifica la estructura de un tipo, el compilador muestra todos los puntos del código que necesitan actualizarse. En proyectos grandes, esta capacidad es fundamental para evolucionar el código sin introducir regresiones:

type Pedido = {
  id: string;
  productos: Producto[];
  total: number;
  estado: "pendiente" | "enviado" | "entregado";
};

function procesarPedido(pedido: Pedido): void {
  console.log(`Procesando pedido ${pedido.id} con total ${pedido.total}`);
}

function cancelarPedido(pedido: Pedido): void {
  if (pedido.estado === "pendiente") {
    console.log(`Pedido ${pedido.id} cancelado`);
  }
}

Si se añade una nueva propiedad obligatoria a Pedido, el compilador senalara cada lugar donde se crea un objeto de ese tipo sin la propiedad nueva. No es necesario buscar manualmente por todo el proyecto.

Documentación implícita

Las anotaciones de tipo funcionan como documentación que el compilador verifica. A diferencia de los comentarios, que pueden quedar desactualizados, los tipos siempre reflejan el estado real del código:

type ResultadoBusqueda = {
  datos: Producto[];
  totalResultados: number;
  página: number;
  porPagina: number;
};

function buscarProductos(
  termino: string,
  página: number,
  porPagina: number
): ResultadoBusqueda {
  const datos: Producto[] = [];
  return {
    datos,
    totalResultados: 0,
    página,
    porPagina
  };
}

La firma de la función buscarProductos documenta exactamente que parámetros recibe y que estructura devuelve. Cualquier desarrollador que use esta función conoce de inmediato el contrato sin necesidad de leer la implementación.

TypeScript frente a JavaScript

Comprender las diferencias entre TypeScript y JavaScript permite evaluar cuando merece la pena utilizar TypeScript y en que escenarios aporta mayor valor.

Tipos estáticos frente a tipos dinámicos

En JavaScript, las variables pueden contener cualquier tipo de valor y cambiar de tipo durante la ejecución del programa. En TypeScript, se puede declarar el tipo esperado y el compilador verifica la coherencia:

// JavaScript permite esto sin errores
let valor = "texto";
// valor = 42; // Valido en JavaScript, error en TypeScript con tipo explícito

// TypeScript con anotación de tipo
let cantidad: number = 10;
// cantidad = "diez"; // Error: Type 'string' is not assignable to type 'number'
console.log(cantidad);

Inferencia de tipos

TypeScript no requiere anotar todos los tipos. El motor de inferencia deduce automáticamente los tipos cuando hay suficiente información contextual:

// TypeScript infiere el tipo automáticamente
const nombre = "Elena";         // tipo: string
const edad = 28;                // tipo: number
const activo = true;            // tipo: boolean
const lenguajes = ["TS", "JS"]; // tipo: string[]

// La inferencia funciona también en funciones
function duplicar(n: number) {
  return n * 2; // TypeScript infiere que el retorno es number
}

const resultado = duplicar(5); // tipo: number
console.log(nombre, edad, activo, lenguajes, resultado);

La inferencia reduce la cantidad de anotaciones necesarias. La recomendación general es anotar los parámetros de funciones y dejar que TypeScript infiera los tipos de retorno y las variables locales cuando el tipo sea evidente.

Comprobaciones de nulos

Con la opción strictNullChecks activada, TypeScript obliga a verificar si un valor puede ser null o undefined antes de usarlo:

function obtenerLongitud(texto: string | null): number {
  if (texto === null) {
    return 0;
  }
  return texto.length;
}

console.log(obtenerLongitud("hola"));
console.log(obtenerLongitud(null));

En JavaScript puro, olvidar está comprobación produce el típico error "Cannot read properties of null". TypeScript previene está categoría de errores de forma sistematica.

Ecosistema y definiciones de tipos

Los principales frameworks del ecosistema JavaScript utilizan TypeScript de forma nativa o proporcionan definiciones de tipos oficiales. Angular está escrito completamente en TypeScript. React, Vue, Next.js y muchos otros ofrecen soporte de primera clase.

Para bibliotecas JavaScript que no incluyen tipos propios, existe el repositorio DefinitelyTyped que proporciona paquetes @types/ con definiciones de tipos mantenidas por la comunidad:

// Instalación de tipos para una biblioteca
// npm install --save-dev @types/lodash

// Tras instalar los tipos, el editor proporciona autocompletado completo
import _ from "lodash";

const números = [3, 1, 4, 1, 5, 9, 2, 6];
const ordenados = _.sortBy(números);
console.log(ordenados);

Cuando usar TypeScript

TypeScript aporta mayor valor en escenarios concretos:

  • Proyectos medianos y grandes: donde múltiples desarrolladores trabajan sobre el mismo código base y necesitan contratos claros entre módulos.
  • Proyectos de larga duración: donde el código debe mantenerse y evolucionar durante meses o anos.
  • APIs y bibliotecas: donde los consumidores del código necesitan saber exactamente que interfaz ofrece cada módulo.
  • Equipos con desarrolladores de distintos niveles: donde el sistema de tipos funciona como una red de seguridad que reduce errores independientemente de la experiencia del autor.

Para scripts puntuales, prototipos rápidos o proyectos muy pequeños, JavaScript puro puede ser suficiente y evita la configuración adicional del compilador.

Ejemplo práctico completo

Para consolidar los conceptos, veamos un ejemplo que combina anotaciones de tipo, tipado estructural e inferencia en un escenario realista:

type Tarea = {
  id: number;
  titulo: string;
  completada: boolean;
  prioridad: "baja" | "media" | "alta";
};

function crearTarea(titulo: string, prioridad: Tarea["prioridad"]): Tarea {
  return {
    id: Date.now(),
    titulo,
    completada: false,
    prioridad
  };
}

function filtrarPorPrioridad(tareas: Tarea[], prioridad: Tarea["prioridad"]): Tarea[] {
  return tareas.filter(t => t.prioridad === prioridad);
}

function completarTarea(tarea: Tarea): Tarea {
  return { ...tarea, completada: true };
}

const listaTareas: Tarea[] = [
  crearTarea("Revisar PR", "alta"),
  crearTarea("Actualizar dependencias", "media"),
  crearTarea("Escribir tests", "alta"),
  crearTarea("Leer documentación", "baja")
];

const tareasAltas = filtrarPorPrioridad(listaTareas, "alta");
console.log("Tareas de prioridad alta:", tareasAltas.length);

const primeraCompletada = completarTarea(tareasAltas[0]);
console.log("Tarea completada:", primeraCompletada.titulo, primeraCompletada.completada);

En este ejemplo, TypeScript verifica que cada tarea tenga todas las propiedades requeridas, que los valores de prioridad sean uno de los tres permitidos y que las funciones reciban los argumentos correctos. Cualquier error en estos aspectos se detecta antes de ejecutar el programa.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TypeScript es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de TypeScript

Explora más contenido relacionado con TypeScript y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Comprender que es TypeScript y su relación con JavaScript como superconjunto tipado. Entender el proceso de compilación de TypeScript a JavaScript y el papel del compilador tsc. Conocer la filosofía del tipado estructural y como TypeScript verifica la forma de los datos. Identificar las ventajas del sistema de tipos para la detección temprana de errores, el autocompletado y la refactorización. Evaluar los escenarios donde TypeScript aporta mayor valor en proyectos profesionales.