TypeScript: Dominando el Tipado Estático

Aprende TypeScript y haz tu código JavaScript más seguro y robusto


TypeScript: Dominando el Tipado Estático
1 Cargando...

TypeScript: Dominando el Tipado Estático

TypeScript es un superset tipado de JavaScript que compila a JavaScript puro. Desarrollado por Microsoft y lanzado en 2012, añade tipado estático opcional y características avanzadas de orientación a objetos a JavaScript, haciendo el desarrollo de aplicaciones a gran escala más seguro y productivo.

Nota: TypeScript está construido sobre JavaScript. Si necesitas revisar los fundamentos, consulta nuestra Guía de JavaScript antes de continuar.

¿Por qué TypeScript?

TypeScript ofrece beneficios significativos para equipos y proyectos de cualquier tamaño:

  1. Detección de Errores en Tiempo de Compilación - Encuentra bugs antes de ejecutar el código
  2. IntelliSense Mejorado - Autocompletado inteligente y documentación inline
  3. Refactorización Segura - Renombra variables y funciones con confianza
  4. Documentación Implícita - Los tipos sirven como documentación viva
  5. Escalabilidad - Mantén proyectos grandes organizados y seguros
  6. Adopción Gradual - Migra desde JavaScript incrementalmente

Tipos Básicos

Tipos Primitivos

// Tipos simples
let nombre: string = "María";
let edad: number = 25;
let activo: boolean = true;
let nulo: null = null;
let indefinido: undefined = undefined;

// Arrays
let numeros: number[] = [1, 2, 3, 4, 5];
let nombres: Array<string> = ["Ana", "Pedro", "Carlos"];

// Tuplas
let coordenada: [number, number] = [10, 20];
let registro: [string, number, boolean] = ["María", 25, true];

// Enum
enum Estado {
  Pendiente = "PENDIENTE",
  Aprobado = "APROBADO",
  Rechazado = "RECHAZADO"
}

let estadoPedido: Estado = Estado.Pendiente;

Tipos Avanzados

// Union Types
type ID = string | number;
let userId: ID = "abc123";
userId = 42; // También válido

// Intersection Types
type Persona = { nombre: string };
type Empleado = { cargo: string };
type EmpleadoPersona = Persona & Empleado;

// Literal Types
type Direccion = "norte" | "sur" | "este" | "oeste";
let direccion: Direccion = "norte";

// Template Literal Types
type NombreEvento = `on${Capitalize<string>}`;

// Nullable Types
let valorOpcional: string | null = null;
valorOpcional = "Valor definido";

Interfaces vs Types

// Interface - ideal para objetos y clases
interface Usuario {
  id: number;
  nombre: string;
  email: string;
  readonly creadoEn: Date;
  direccion?: Direccion; // Propiedad opcional
}

interface Direccion {
  calle: string;
  ciudad: string;
  pais: string;
}

// Extensión de interface
interface Admin extends Usuario {
  permisos: string[];
  nivel: "junior" | "senior" | "master";
}

// Type alias - más flexible
type Resultado<T> = 
  | { exito: true; datos: T }
  | { exito: false; error: string };

type Callback<T> = (datos: T) => void;

Generics

// Función genérica
function primero<T>(array: T[]): T | undefined {
  return array[0];
}

const primerNumero = primero([1, 2, 3]); // number
const primeraString = primero(["a", "b", "c"]); // string

// Clase genérica
class Pila<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }
}

// Constraints (restricciones)
interface ConId {
  id: number;
}

function buscarPorId<T extends ConId>(items: T[], id: number): T | undefined {
  return items.find(item => item.id === id);
}

// Utility Types
type UsuarioSoloLectura = Readonly<Usuario>;
type UsuarioParcial = Partial<Usuario>;
type UsuarioSinDireccion = Omit<Usuario, "direccion">;
type SoloNombreEmail = Pick<Usuario, "nombre" | "email">;

Funciones Tipadas

// Función con tipos explícitos
function calcularDescuento(
  precio: number,
  porcentaje: number
): number {
  return precio * (1 - porcentaje / 100);
}

// Arrow function tipada
const multiplicar = (a: number, b: number): number => a * b;

// Sobrecarga de funciones
function procesar(valor: string): string;
function procesar(valor: number): number;
function procesar(valor: string | number): string | number {
  if (typeof valor === "string") {
    return valor.toUpperCase();
  }
  return valor * 2;
}

// Type guards
function esString(valor: unknown): valor is string {
  return typeof valor === "string";
}

function formatearValor(valor: unknown): string {
  if (esString(valor)) {
    return valor.trim();
  }
  return String(valor);
}

Clases con TypeScript

abstract class Entidad {
  constructor(
    public readonly id: string,
    public creadoEn: Date = new Date()
  ) {}

  abstract validar(): boolean;
}

class Producto extends Entidad {
  constructor(
    id: string,
    public nombre: string,
    public precio: number,
    private _stock: number = 0
  ) {
    super(id);
  }

  get stock(): number {
    return this._stock;
  }

  set stock(valor: number) {
    if (valor < 0) {
      throw new Error("El stock no puede ser negativo");
    }
    this._stock = valor;
  }

  validar(): boolean {
    return this.nombre.length > 0 && this.precio > 0;
  }

  aplicarDescuento(porcentaje: number): number {
    return this.precio * (1 - porcentaje / 100);
  }
}

// Implementando interfaces
interface Serializable {
  toJSON(): string;
}

class Item implements Serializable {
  constructor(public nombre: string) {}

  toJSON(): string {
    return JSON.stringify({ nombre: this.nombre });
  }
}

Configuración del Proyecto

tsconfig.json Recomendado

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Lista de Verificación de Aprendizaje

  • Dominar tipos primitivos y arrays
  • Entender interfaces y type aliases
  • Aprender generics y constraints
  • Estudiar utility types (Partial, Readonly, Pick, Omit)
  • Practicar type guards y narrowing
  • Configurar proyectos con tsconfig.json
  • Migrar un proyecto JavaScript existente

Errores Comunes a Evitar

  • Usar any en todos lados → Usa unknown o tipos específicos
  • Ignorar errores de compilación → Corrige todos los errores de tipo
  • No usar strict mode → Siempe activa strict: true
  • Duplicar tipos → Usa utility types para derivar tipos

Recursos Esenciales

Cita

“TypeScript es JavaScript que escala.” - Anders Hejlsberg, creador de TypeScript


¡TypeScript transforma la manera en que escribes JavaScript. Invierte tiempo aprendiendo sus características y tu productividad aumentará significativamente!