Cheat Sheet completa de TypeScript


Esta cheat sheet de TypeScript es una referencia rápida y práctica para entender sus tipos, inferencias, interfaces, genéricos y funcionalidades modernas.
Ideal para pasar de JavaScript a TypeScript de forma fluida.

Tipos básicos

Los tipos básicos son la base de TypeScript y te permiten describir con claridad qué clase de dato espera cada variable.

// 🚀 TIPOS BÁSICOS

// Inferencia automática
let nombre = 'Carlos'; // string
let edad = 42; // number
let activo = true; // boolean

// Tipado explícito
let ciudad: string = 'Zaragoza';
let puntuacion: number = 98.5;
let registrado: boolean = false;

// Null y undefined
let nada: null = null;
let indefinido: undefined = undefined;

// Arrays
let numeros: number[] = [1, 2, 3];
let frutas: Array<string> = ['manzana', 'pera'];

// Tuplas
let usuario: [string, number] = ['Carlos', 42];

// Any (⚠️ evitarlo)
let variable: any = 123;
variable = 'ahora soy texto';

// Unknown (más seguro que any)
let valor: unknown = 'texto';
if (typeof valor === 'string') {
  console.log(valor.toUpperCase());
}

// Never (para errores o funciones que no devuelven)
function error(mensaje: string): never {
  throw new Error(mensaje);
}

// Void (sin retorno)
function saludar(): void {
  console.log('Hola mundo');
}

Tipos avanzados

Los tipos avanzados amplían el modelado de datos con uniones, aliases, literales e intersecciones.

// 🚀 TIPOS AVANZADOS

// Union types
let id: number | string;
id = 123;
id = 'ABC';

// Type alias
type ID = number | string;
let usuarioID: ID = 42;

// Literal types
let rol: 'admin' | 'user' | 'guest';
rol = 'admin';

// Optional & default
function saluda(nombre: string, edad?: number): void {
  console.log(`Hola ${nombre} ${edad ?? ''}`);
}

// Intersection types
type Persona = { nombre: string };
type Trabajador = { empresa: string };
type Empleado = Persona & Trabajador;
const empleado: Empleado = { nombre: 'Ana', empresa: 'TechCorp' };

// Enum
enum Estado {
  Activo,
  Inactivo,
  Pendiente,
}
let estadoActual: Estado = Estado.Activo;

// Enum con valores personalizados
enum Rol {
  Admin = 'ADMIN',
  Editor = 'EDITOR',
  User = 'USER',
}

Funciones

TypeScript tipa parámetros, retornos y firmas de función para que el comportamiento quede claro desde el principio.

// 🚀 FUNCIONES EN TYPESCRIPT

// Tipado de parámetros y retorno
function sumar(a: number, b: number): number {
  return a + b;
}

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

// Parámetros opcionales
function log(mensaje: string, usuario?: string) {
  console.log(usuario ? `${usuario}: ${mensaje}` : mensaje);
}

// Parámetros por defecto
function saluda2(nombre: string = 'desconocido') {
  console.log(`Hola ${nombre}`);
}

// Rest parameters
function total(...numeros: number[]): number {
  return numeros.reduce((acc, n) => acc + n, 0);
}

// Tipado de funciones
type Operacion = (a: number, b: number) => number;
const restar: Operacion = (a, b) => a - b;

Objetos, interfaces y tipos

Interfaces y type aliases sirven para definir estructuras reutilizables y mantener consistencia entre objetos.

// 🚀 INTERFACES Y TYPE ALIAS

// Interface
interface Usuario {
  id: number;
  nombre: string;
  email?: string; // opcional
}

const u1: Usuario = { id: 1, nombre: 'Carlos' };

// Herencia de interfaces
interface Admin extends Usuario {
  permisos: string[];
}
const admin: Admin = { id: 2, nombre: 'Sara', permisos: ['read', 'write'] };

// Type alias vs interface
type Producto = {
  nombre: string;
  precio: number;
};

// Index signature
interface Diccionario {
  [clave: string]: string;
}

const traducciones: Diccionario = {
  hola: 'hello',
  adios: 'bye',
};

Clases

Las clases en TypeScript añaden tipado, modificadores de acceso y una herencia más explícita sobre JavaScript.

// 🚀 CLASES

class Persona {
  // Propiedades con modificadores
  public nombre: string;
  protected edad: number;
  private dni: string;

  constructor(nombre: string, edad: number, dni: string) {
    this.nombre = nombre;
    this.edad = edad;
    this.dni = dni;
  }

  saludar(): void {
    console.log(`Hola, soy ${this.nombre}`);
  }
}

const p1 = new Persona('Carlos', 43, '12345678A');

// Herencia
class Empleado extends Persona {
  private puesto: string;

  constructor(nombre: string, edad: number, dni: string, puesto: string) {
    super(nombre, edad, dni);
    this.puesto = puesto;
  }

  trabajar(): void {
    console.log(`${this.nombre} trabaja como ${this.puesto}`);
  }
}

// Propiedades de solo lectura y estáticas
class Config {
  readonly version = '1.0.0';
  static autor = 'TypeScript';
}

Genéricos

Los genéricos permiten reutilizar funciones, tipos o interfaces sin perder precisión en el tipado.

// 🚀 GENÉRICOS

// Función genérica
function identidad<T>(valor: T): T {
  return valor;
}

const texto = identidad('Hola');
const numero = identidad(123);

// Genérico con restricción
function getPropiedad<T, K extends keyof T>(obj: T, clave: K): T[K] {
  return obj[clave];
}

const persona = { nombre: 'Carlos', edad: 43 };
const edad = getPropiedad(persona, 'edad');

// Interfaces genéricas
interface Caja<T> {
  contenido: T;
}

const cajaDeTexto: Caja<string> = { contenido: 'Hola' };
const cajaDeNumero: Caja<number> = { contenido: 99 };

Módulos e imports

Los módulos organizan el código en archivos reutilizables y facilitan importar solo lo que cada parte necesita.

// 🚀 MÓDULOS

// archivo utils.ts
export function sumar(a: number, b: number): number {
  return a + b;
}

export const PI = 3.1416;

// archivo main.ts
import { sumar, PI } from './utils';

console.log(sumar(2, 3), PI);

// Export default
export default function saluda(nombre: string) {
  console.log(`Hola ${nombre}`);
}

// Import default
import saluda from './utils';

Utility Types

Los utility types resuelven transformaciones muy comunes sobre tipos sin tener que reescribir estructuras enteras.

// 🚀 UTILITY TYPES MÁS ÚTILES

interface Usuario {
  id: number;
  nombre: string;
  email?: string;
  activo: boolean;
}

// Partial → convierte todas las props en opcionales
type UsuarioEditable = Partial<Usuario>;

// Required → todas las props obligatorias
type UsuarioCompleto = Required<Usuario>;

// Pick → selecciona propiedades específicas
type UsuarioMini = Pick<Usuario, 'id' | 'nombre'>;

// Omit → excluye propiedades
type UsuarioSinEmail = Omit<Usuario, 'email'>;

// Readonly → propiedades inmutables
type UsuarioSoloLectura = Readonly<Usuario>;

// Record → crea un mapa de claves y valores
type DiccionarioUsuarios = Record<string, Usuario>;

// ReturnType → obtiene el tipo de retorno de una función
type Resultado = ReturnType<typeof sumar>;

Narrowing (control de tipos)

El narrowing reduce un tipo amplio a otro más concreto según comprobaciones reales del código.

// 🚀 TYPE NARROWING

function procesar(valor: string | number) {
  if (typeof valor === 'string') {
    return valor.toUpperCase();
  }
  return valor * 2;
}

// instanceof
class Perro {
  ladra() {}
}
class Gato {
  maulla() {}
}

function hablar(animal: Perro | Gato) {
  if (animal instanceof Perro) {
    animal.ladra();
  } else {
    animal.maulla();
  }
}

// in
interface Carro {
  ruedas: number;
}
interface Barco {
  anclas: number;
}

function mover(vehiculo: Carro | Barco) {
  if ('ruedas' in vehiculo) {
    console.log('Es un carro');
  } else {
    console.log('Es un barco');
  }
}

Type Assertions y as const

Las assertions sirven para guiar al compilador, y as const fija valores para inferir tipos más precisos.

// 🚀 TYPE ASSERTIONS

// Forzar tipo
const valor = document.getElementById('input') as HTMLInputElement;
valor.value = 'Hola';

// Non-null assertion (!)
const btn = document.querySelector('button')!;
btn.disabled = true;

// const assertions
const COLORES = {
  primario: '#ff99a7',
  secundario: '#ffe8b9',
} as const;

// Literal types inferidos
type Colores = (typeof COLORES)[keyof typeof COLORES];

Tipos condicionales e inferencia

Los tipos condicionales permiten construir lógica de tipos y reutilizar patrones más avanzados a nivel estático.

// 🚀 TIPOS CONDICIONALES

type EsString<T> = T extends string ? 'es string' : 'no es string';

type A = EsString<string>; // "es string"
type B = EsString<number>; // "no es string"

// Inferencia en tipos
type Retorno<T> = T extends (...args: any[]) => infer R ? R : never;
type R1 = Retorno<() => number>; // number
type R2 = Retorno<() => string>; // string

Configuración básica tsconfig.json

tsconfig.json define cómo compila TypeScript y qué nivel de seguridad o compatibilidad quieres en el proyecto.

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  }
}

Buenas prácticas

Estas prácticas ayudan a sacar partido a TypeScript sin convertir el código en algo más rígido de la cuenta.

  • Usa unknown en lugar de any
  • Evita castings innecesarios (as)
  • Declara tipos con type y estructuras con interface
  • Usa strictNullChecks activado
  • Separa tipos y lógica en carpetas types/ o interfaces/
  • Aprovecha enum o as const para constantes
  • Prefiere inferencia de tipos (TypeScript es muy bueno en esto)