Introducción a TypeScript

TypeScript es un lenguaje de programación de código abierto desarrollado por Microsoft. Es un superconjunto de JavaScript que, además de ser totalmente compatible con la sintaxis de JavaScript, añade un sistema de tipos estáticos opcional y capacidades de programación orientada a objetos basada en clases.

El código TypeScript se compila finalmente a JavaScript puro, el cual puede ejecutarse en cualquier entorno compatible con JavaScript, incluidos navegadores, Node.js y dispositivos móviles.


¿Por qué es necesario TypeScript?

JavaScript es un lenguaje de tipado dinámico; el tipo de una variable solo se determina en tiempo de ejecución.

Esta flexibilidad funciona muy bien en proyectos pequeños, pero a medida que el proyecto crece, los problemas comienzan a aparecer:

Escenario problemáticoLas dificultades de JavaScriptLa solución de TypeScript
Pasar un tipo incorrecto a un parámetro de funciónEl error solo aparece en tiempo de ejecución, difícil de detectar con antelaciónEl error aparece en la compilación, con aviso en tiempo real del IDE
Acceder a una propiedad inexistentedevuelveundefined, comportamiento impredecibleEl compilador muestra el error directamente y rechaza el código
Refactorización de proyectos grandesCambias un lugar y no sabes qué podría romperseEl sistema de tipos rastrea automáticamente todas las referencias
Colaboración en equipoQué parámetros acepta una función y qué devuelve depende únicamente de comentarios o documentaciónLa firma de tipos es la documentación; el IDE ofrece autocompletado automáticamente
Legibilidad del códigoCon ver la definición de la función no se puede saber directamente la estructura de datosLas interfaces y los alias de tipos hacen que la estructura de datos sea clara de un vistazo

El objetivo esencial de TypeScript no es reemplazar a JavaScript, sino hacer que los proyectos JavaScript a gran escala sean manejables y mantenibles. Es una 'red de seguridad' para JavaScript, no un competidor.

Veamos el ejemplo más intuitivo:

Ejemplo

// JavaScript: el error se produce solo en tiempo de ejecución
function greet(name) {
    return "Hello, " + name.toUpperCase();
}

greet(123); // Error en tiempo de ejecución: name.toUpperCase is not a function

Ejemplo

// TypeScript: el error se detecta en tiempo de compilación
function greet(name: string): string {
    return "Hello, " + name.toUpperCase();
}

greet(123); // Error de compilación: Argument of type 'number' is not assignable to parameter of type 'string'
greet("ejemplo"); // Correcto: Hello, EJEMPLO

Relación entre TypeScript y JavaScript

La relación entre TypeScript y JavaScript se puede resumir en una frase:TypeScript es un superconjunto de JavaScript, es decir, todo código JavaScript válido es también código TypeScript válido.

Representación de la relación de conjuntos

JavaScript (todo el código JS)
⊂ TypeScript (JS + sistema de tipos + nuevas características)
⊂ Producto de compilación (JavaScript estándar, se puede ejecutar en cualquier entorno)

Comparación de las diferencias clave entre ambos:

Criterio de comparaciónJavaScriptTypeScript
Sistema de tiposTipado dinámico, determinado en tiempo de ejecuciónTipado estático, verificado en tiempo de compilación (opcional)
Forma de ejecuciónSe ejecuta directamente en el navegador / Node.jsRequiere compilar a JS antes de ejecutarse
Momento de detección de erroresTiempo de ejecuciónTiempo de compilación (detección anticipada)
Soporte de IDEAutocompletado básicoInferencia de tipos sólida, autocompletado preciso, soporte de refactorización
Curva de aprendizajeRelativamente suaveRequiere aprender también el sistema de tipos
Compatibilidad con JS existente—Totalmente compatible, migración progresiva posible
Extensión de archivo.js.tso.tsx(incluye JSX)

TypeScript admite la 'adopción progresiva': no es necesario reescribir todo el proyecto de una vez. Puedes primero.jscambiarlo a.ts, y añadir gradualmente tipos a los módulos clave; el código existente continuará funcionando con normalidad.


Características principales

TypeScript introduce un sistema de tipos completo sobre JavaScript; las siguientes son las características principales más utilizadas.

Anotaciones de tipos básicos

Se declara el tipo con dos puntos después de variables, parámetros de función y valores de retorno; esta es la forma más básica de escribir TypeScript.

Ejemplo

// Tipos básicos: number, string, boolean, null, undefined, symbol, bigint
let age: number = 25;
let username: string = "ejemplo";
let isActive: boolean = true;

// Tipos de array, dos formas equivalentes
let scores: number[] = [90, 85, 92];
let tags: Array<string> = ["typescript", "javascript"];

// Tupla: array con longitud y tipos fijos
let point: [number, number] = [10, 20];
let entry: [string, number] = ["EJEMPLO", 100];

// Función: tipo de parámetros + tipo de valor de retorno
function add(a: number, b: number): number {
    return a + b;
}

// void: función sin valor de retorno
function log(msg: string): void {
    console.log(msg);
}

// Parámetro opcional: añadir ? después del nombre del parámetro
function greet(name: string, title?: string): string {
    return title ? `${title} ${name}` : name;
}

console.log(greet("EJEMPLO"));          // Salida: EJEMPLO
console.log(greet("ejemplo", "Mr."));  // Salida: Mr. ejemplo

Interfaz (Interface)

Las interfaces se usan para describir la 'forma' (Shape) de un objeto y definir qué propiedades y métodos debe tener.

Ejemplo

// Definición de interfaz: describe la estructura del objeto usuario
interface User {
    id: number;          // Requerido
    name: string;        // Requerido
    email?: string;      // Opcional, marcado con ?
    readonly role: string; // Solo lectura; no se puede modificar después de asignarlo
}

// El parámetro de función usa el tipo de interfaz
function printUser(user: User): void {
    console.log(`ID: ${user.id}, Name: ${user.name}`);
    if (user.email) {
        console.log(`Email: ${user.email}`);
    }
}

const admin: User = {
    id: 1,
    name: "EJEMPLO",
    email: "[email protected]",
    role: "admin",
};

printUser(admin);
// Salida: ID: 1, Name: EJEMPLO
// Salida: Email: [email protected]

// admin.role = "user"; // Error: Cannot assign to 'role' because it is a read-only property.

// Herencia de interfaces
interface AdminUser extends User {
    permissions: string[];
}

Alias de tipo (Type Alias)

Los alias de tipo se crean con latypepalabra clave, y pueden definir alias para cualquier tipo, incluidas estructuras complejas como uniones e intersecciones de tipos.

Ejemplo

// Unión de tipos: la variable puede ser uno de varios tipos
type ID = string | number;

let userId: ID = "abc-123"; // Válido
userId = 456;               // También válido

// Tipo literal: restringe la variable a solo valores específicos
type Direction = "up" | "down" | "left" | "right";
type Status = "pending" | "active" | "inactive";

function move(dir: Direction): void {
    console.log(`Moving ${dir}`);
}

move("up");    // Correcto
// move("diagonal"); // Error: no está dentro del tipo literal

// Intersección de tipos: combina varios tipos
type WithTimestamp = {
    createdAt: Date;
    updatedAt: Date;
};

type UserRecord = User & WithTimestamp; // Tiene todas las propiedades de User y WithTimestamp a la vez

// Alias de tipo para funciones
type Transformer<T, U> = (input: T) => U;
const toNumber: Transformer<string, number> = (s) => parseInt(s, 10);

Genéricos (Generics)

Los genéricos permiten escribir componentes reutilizables manteniendo la seguridad de tipos. Puedes entender los genéricos como "variables de tipos": el tipo concreto se pasa al utilizarlo.

Ejemplo

// Sin genéricos: solo puede manejar el tipo number
function firstNumber(arr: number[]): number {
    return arr[0];
}

// Usando genéricos: T es un parámetro de tipo, se determina en la llamada
function first<T>(arr: T[]): T {
    return arr[0];
}

const n = first<number>([1, 2, 3]);    // El tipo de n es number
const s = first<string>(["a", "b"]);  // El tipo de s es string
const inferred = first([true, false]); // TypeScript infiere automáticamente T como boolean

// Interfaz genérica
interface ApiResponse<T> {
    data: T;
    status: number;
    message: string;
}

// Usando una interfaz genérica
const userResponse: ApiResponse<User> = {
    data: { id: 1, name: "EJEMPLO", role: "admin" },
    status: 200,
    message: "success",
};

// Restricción de genéricos: T debe tener una propiedad id
function getById<T extends { id: number }>(items: T[], id: number): T | undefined {
    return items.find(item => item.id === id);
}

Enumeración (Enum)

Las enumeraciones se usan para definir un conjunto de constantes con nombre, haciendo que los "números mágicos" o "cadenas mágicas" en el código tengan significado.

Ejemplo

// Enumeración numérica (por defecto comienza en 0 y se incrementa)
enum Direction {
    Up,     // 0
    Down,   // 1
    Left,   // 2
    Right,  // 3
}

console.log(Direction.Up);    // Salida: 0
console.log(Direction[0]);    // Salida: "Up" (mapeo inverso)

// Enumeración de cadenas (más recomendada, los valores son más legibles al depurar)
enum Color {
    Red = "RED",
    Green = "GREEN",
    Blue = "BLUE",
}

function paint(color: Color): void {
    console.log(`Painting in ${color}`);
}

paint(Color.Red); // Salida: Painting in RED
// paint("red"); // Error: la cadena "red" no es del tipo Color

// Enumeración const: se incluye en línea tras la compilación, reduciendo la sobrecarga en tiempo de ejecución
const enum HttpStatus {
    OK = 200,
    NotFound = 404,
    InternalError = 500,
}

const status: HttpStatus = HttpStatus.OK; // Tras la compilación se reemplaza directamente por el número 200

Inferencia de tipos

TypeScript no requiere anotar manualmente el tipo de cada variable; el compilador lo infiere automáticamente según la asignación.

Ejemplo

// TypeScript infiere automáticamente los tipos de las variables, sin necesidad de anotaciones explícitas
let count = 0;            // Se infiere como number
let name = "EJEMPLO";      // Se infiere como string
let flag = true;          // Se infiere como boolean

// Infiere el tipo de los elementos del array
let numbers = [1, 2, 3];  // Se infiere como number[]

// Infiere el tipo de retorno de la función
function double(n: number) {  // El valor de retorno se infiere automáticamente como number
    return n * 2;
}

// Inferencia de literales de objeto
const config = {
    host: "localhost",    // string
    port: 3000,           // number
    debug: false,         // boolean
};

// config.port = "3000"; // Error: Type 'string' is not assignable to type 'number'.

Un consejo práctico: los parámetros de las funciones suelen necesitar anotaciones explícitas de tipo (porque quien las llama no puede inferir el tipo a partir de los valores de los argumentos), mientras que las variables locales y los valores de retorno pueden depender de la inferencia en la mayoría de los casos, sin necesidad de anotarlos todos manualmente.

Clases y modificadores de acceso

TypeScript es totalmente compatible con la sintaxis de clases de ES6 y añadepublic、private、protected、readonlycuatro modificadores de acceso.

Ejemplo

class Animal {
    readonly name: string;         // Solo lectura, no se puede modificar después de la inicialización
    private age: number;           // Privado, solo se puede acceder dentro de la clase
    protected species: string;     // Protegido, accesible para las subclases

    constructor(name: string, age: number, species: string) {
        this.name = name;
        this.age = age;
        this.species = species;
    }

    // Método public (por defecto es public, se puede omitir)
    public introduce(): string {
        return `I'm ${this.name}, a ${this.species}.`;
    }

// Getter: llama al método como si se accediera a una propiedad
    get info(): string {
        return `${this.name} (${this.age} years old)`;
    }
}

class Dog extends Animal {
    private breed: string;

    constructor(name: string, age: number, breed: string) {
super(name, age, "Canis lupus familiaris"); // Llama al constructor de la clase padre
        this.breed = breed;
    }

// La subclase puede acceder a la propiedad protected
    describe(): string {
        return `${this.name} is a ${this.species}, breed: ${this.breed}`;
    }
}

const dog = new Dog("EJEMPLO", 3, "Labrador");
console.log(dog.introduce()); // Salida: I'
m EJEMPLO, a Canis lupus familiaris.
console.log(dog.info);         // Salida: EJEMPLO (3 years old)
// console.log(dog.age); // Error: la propiedad privada no se puede acceder desde fuera

Decorador (Decorator)

Los decoradores son una sintaxis de metaprogramación que permite añadir comportamientos adicionales a clases, métodos y propiedades; se usan comúnmente en frameworks como Angular y NestJS.

TypeScript 5.0 ha implementado los decoradores como estándar oficial (propuesta Stage 3), por lo que ya no es necesario activar laexperimentalDecoratorsflag.

Ejemplo

// Decorador de clase: se ejecuta al definir la clase
function sealed(constructor: Function) {
    Object.seal(constructor);         // Prohíbe añadir nuevas propiedades
    Object.seal(constructor.prototype);
}

// Decorador de método: se puede usar para registro de logs, verificación de permisos, etc.
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`Calling ${propertyKey} with args:`, args);
        const result = original.apply(this, args);
        console.log(`${propertyKey} returned:`, result);
        return result;
    };
}

@sealed
class Calculator {
    @log
    add(a: number, b: number): number {
        return a + b;
    }
}

const calc = new Calculator();
calc.add(1, 2);
// Salida: Calling add with args: [ 1, 2 ]
// Salida: add returned: 3

Áreas de aplicación

TypeScript, gracias a su total compatibilidad con JavaScript, puede usarse en casi cualquier lugar donde JavaScript pueda ejecutarse, y aporta beneficios adicionales en proyectos grandes.

Desarrollo web frontend

Este es el escenario más común para TypeScript. Los tres frameworks frontend principales ofrecen soporte de primera clase para TypeScript:

FrameworkSoporte de TypeScriptCasos de uso típicos
AngularLenguaje oficial, usa TypeScript por defecto, no se puede omitirSPA empresariales, sistemas de administración
ReactProporcionado oficialmente@types/react, Create React App y Vite incluyen plantillas de TypeScript integradas.Comercio electrónico, plataformas de contenido, aplicaciones de gestión
VueEl código central de Vue 3 está reescrito en TypeScript, y la Composition API ha mejorado notablemente la compatibilidad con TypeScript.Proyectos medianos y pequeños, migración progresiva
Next.js / NuxtSoporte integrado de TypeScript, activado por defecto en proyectos nuevos.Aplicaciones full-stack SSR/SSG

Desarrollo backend con Node.js

TypeScript es igualmente popular en el desarrollo backend con Node.js.NestJSEs el framework backend de TypeScript más popular, utiliza una arquitectura modular similar a Angular y tiene soporte integrado de inyección de dependencias y decoradores.

Además,DenoEl runtime es compatible de forma nativa con TypeScript desde el primer día, y puede ejecutarse directamente sin configuración alguna..tsarchivos.BunIgualmente incluye soporte integrado de TypeScript.

Herramientas de línea de comandos y scripts

Con la ayuda dets-node、tsxherramientas como estas, el código TypeScript se puede ejecutar directamente sin compilación previa, ideal para escribir scripts de build y herramientas CLI.

Móvil y multiplataforma

React NativeSoporte completo de TypeScript; muchas aplicaciones móviles empresariales (como Microsoft Office móvil, Shopify, etc.) utilizan esta pila tecnológica.ExpoLa plantilla de nuevos proyectos también se basa en TypeScript por defecto.

Desarrollo de juegos y gráficos

Babylon.jsEl motor 3D de Microsoft está completamente escrito en TypeScript y trata las definiciones de tipos de TypeScript como ciudadanos de primera clase.PhaserLos motores de juegos 2D como estos también ofrecen definiciones de tipos completas.


Historia del desarrollo

El nacimiento y el crecimiento de TypeScript están estrechamente relacionados con la evolución del ecosistema de JavaScript; cada lanzamiento de una versión importante está impulsado por necesidades de ingeniería claras.

Orígenes (2010-2012)

La historia de TypeScript comienza con un desafío de ingeniería en Microsoft: cómo hacer mantenibles los grandes proyectos de JavaScript.

DiseñadorAnders HejlsbergEs una leyenda de la industria: arquitecto jefe de C# y creador de Turbo Pascal y Delphi. Comenzó a diseñar este lenguaje alrededor de 2010, con el objetivo central de introducir la verificación estática de tipos sin romper la compatibilidad con JavaScript.

Otro contexto del lanzamiento de TypeScript por Microsoft fue la publicación de Windows 8: las aplicaciones podían desarrollarse con HTML + JavaScript, y Microsoft quería atraer a los programadores de .NET, por lo que mucha de la sintaxis de TypeScript se mantuvo deliberadamente similar a C# y .NET.

En octubre de 2012, TypeScript 0.8 se publicó oficialmente, tras unos dos años de desarrollo interno en Microsoft.

Primeras versiones (2013-2015)

FechaVersiónHitos importantes
2013-060.9Lanzamiento de la versión estable oficial, gran mejora de rendimiento, mejor integración con IDE.
2014-041.0Primera versión estable oficial; introduce clases, interfaces y módulos, con soporte para compilar a JavaScript estándar.
2014-07—El código del compilador de TypeScript se vuelve de código abierto, alojado en GitHub, aceptando contribuciones de la comunidad.
2015-04—Microsoft lanza Visual Studio Code, con soporte profundo integrado para TypeScript; ambos se complementan mutuamente.
2015-071.5Introduce soporte de sintaxis de módulos ES6, decoradores (experimental) y espacios de nombres.

Crecimiento acelerado (2016-2019)

Esta etapa fue clave para que TypeScript pasara de ser una herramienta de nicho a convertirse en mainstream; el impulso principal provino de las decisiones del ecosistema de frameworks.

FechaVersión / EventoHito
2016-09TypeScript 2.0Introducción de los tipos no nulos (--strictNullChecks), una de las características más importantes de la seguridad de tipos de TypeScript; introducción de las uniones discriminadas
2016Lanzamiento de Angular 2El equipo de Google Angular anunció la adopción de TypeScript como lenguaje de desarrollo oficial, llevando TypeScript a la atención del público general
2017Serie TypeScript 2.xSe introdujeron sucesivamente los tipos condicionales, los tipos mapeados y la palabra clave infer, lo que mejoró enormemente la capacidad expresiva del sistema de tipos
2018-07TypeScript 3.0Referencias de proyectos (Project References), con soporte para monorepos de gran tamaño; se introdujo el tipo unknown (un tipo superior más seguro que any)
2019DefinitelyTypedEl repositorio de definiciones de tipos mantenido por la comunidad, DefinitelyTyped (@types/*) supera los 7000 paquetes y cubre prácticamente todas las bibliotecas npm principales

Madurez y popularización (2020-2022)

FechaVersión / EventoContenido importante
2020-08TypeScript 4.0Tipos de tupla variádicos y elementos de tupla etiquetados; la experiencia del editor mejoró significativamente
2021Serie TypeScript 4.xTipos de literales de plantilla (Template Literal Types), mejora de los tipos de utilidad incorporados,noImplicitOverridey otras mejoras del modo estricto
2022Encuesta State of JSLa tasa de uso de TypeScript superó por primera vez a la de JavaScript puro, convirtiéndose en el lenguaje superconjunto más popular del ecosistema JS
2022Popularización de Vue 3 / ViteEl núcleo de Vue 3 fue reescrito con TypeScript y, junto con Vite, llevó la experiencia de TypeScript en el desarrollo frontend a un nuevo nivel

Etapa moderna (2023-presente)

FechaVersiónCaracterísticas importantes
2023-03TypeScript 5.0Decoradores modernos (estándar Stage 3), parámetros de tipo const, todos los enums se actualizaron a enums de unión, con una mejora significativa del rendimiento
2023-08TypeScript 5.2Se introdujo Explicit Resource Management (usingpalabra clave), que resuelve el problema de la limpieza determinista de recursos como conexiones de bases de datos y manejadores de archivos
2024-03TypeScript 5.4Mejoras en el estrechamiento de tipos en closures,NoInfertipos de utilidad
2024-06TypeScript 5.5Inferencia de predicados de tipo y comprobación de sintaxis de expresiones regulares, lo que permite que el sistema de tipos comprenda la lógica del código con mayor precisión
2024-11TypeScript 5.7Soporte para--target es2024una detección más fiable de variables no inicializadas
2025-03TypeScript 5.8Comprobación mejorada de valores de retorno en tipos de acceso condicional e indexado; se admite--module nodenextbajo ... medianterequire()la carga de módulos ESM (requiere Node.js 22+)

Perspectivas futuras: reescribir el compilador en Go

A principios de 2025, Microsoft anunció una decisión importante: reescribir el compilador de TypeScript en el lenguaje Go, con el nombre clave del proyectoCorsa。

Microsoft afirmó que se espera que el compilador reescrito ofrezca una mejora de rendimiento de más de 10 veces, y que el tiempo de compilación de proyectos grandes se reduzca de minutos a segundos.

Según el plan, la versión en Go se publicará oficialmente en TypeScript 7.x, mientras que las versiones actuales 5.x / 6.x de TypeScript continuarán con su iteración y mantenimiento normales. Se espera que la reescritura esté terminada a finales de 2025.

Esta reescritura no cambiará la sintaxis ni el sistema de tipos del propio lenguaje TypeScript; es una actualización transparente para los desarrolladores: tu código no necesita ningún cambio, solo la velocidad de compilación mejora drásticamente.


Comparación de TypeScript con otros lenguajes de tipado fuerte

Si tienes experiencia con otros lenguajes de tipado fuerte, la siguiente comparación puede ayudarte a situar rápidamente la filosofía de diseño de TypeScript.

Elemento de comparaciónTypeScriptJava / C#Go
Sistema de tiposTipado estructural (duck typing)Tipado nominal (debe declararse explícitamente la relación de herencia)Tipado estructural (interfaces implícitas)
Seguridad de valores nulosAl habilitarstrictNullChecksse admiteJava requiere anotaciones u Optional; C# 8+ lo admiteMediante valores de error y comprobaciones de nil
GenéricosAdmite, sintaxis similar a Java/C#Admite; Java tiene limitaciones por borrado de tiposAdmite desde Go 1.18+, con sintaxis relativamente sencilla
Artefacto de compilaciónJavaScript (se ejecuta en entornos JS)Bytecode (se ejecuta en JVM / CLR)Código máquina nativo
Comprobación de tipos en tiempo de ejecuciónNo (la información de tipos se elimina tras la compilación)Sí (mecanismo de reflexión)Ninguno
Curva de aprendizajeAmigable para desarrolladores de JS, se puede adoptar de forma gradualEmpinada para principiantesRelativamente simple, curva de aprendizaje media

TypeScript utilizaun sistema de tipado estructural(Structural Typing): si dos tipos tienen la misma "forma", se consideran compatibles, sin necesidad de declarar explícitamente relaciones de herencia. Esto difiere esencialmente del tipado nominal (Nominal Typing) de Java/C#, y es también la razón clave por la que TypeScript puede interoperar sin problemas con JavaScript.


Limitaciones de TypeScript

TypeScript no es una bala de plata; conocer sus límites es igualmente importante.

LimitaciónDescripciónCómo abordarlo
Sin tipos en tiempo de ejecuciónToda la información de tipos se elimina después de la compilación, por lo que en tiempo de ejecución no se puede depender de los tipos para tomar decisionesCuando se necesite validación en tiempo de ejecución, usarzod、io-tsy otras bibliotecas
Paso de compilaciónEn comparación con JS puro, añade un paso de compilación adicional, lo que aumenta la complejidad del proyectoLas herramientas de construcción modernas (Vite, esbuild) ya ofrecen una buena optimización para ello
El tipo any como vía de escapeEl abuso deanyhará que la comprobación de tipos sea una formalidad vacíaHabilitarnoImplicitAnyystrictel modo, junto con reglas de ESLint
Barrera de entrada de la gimnasia de tiposLos tipos condicionales y mapeados complejos no son amigables para los principiantesLa mayoría del código de negocio no necesita tipos avanzados; basta con aprender de forma progresiva
Compatibilidad con bibliotecas de tercerosAlgunas bibliotecas antiguas carecen de definiciones de tipos, por lo que hay que escribir los archivos .d.ts manualmentePrimero busca en@types/*si de verdad no existe, escribe manualmente el archivo de declaraciones
Otras extensiones