logo-andres-saumet

logo-andres-saumet
TypeScript Avanzado: Tipos, Genéricos y Decoradores
7 de febrero de 2026

TypeScript Avanzado: Tipos, Genéricos y Decoradores

Domina TypeScript avanzado. Aprende tipos complejos, genéricos, decoradores y patrones de diseño en TypeScript.

AS
Andres Saumet
typescriptjavascriptdevelopmentadvanced

TypeScript Avanzado: Tipos, Genéricos y Decoradores

TypeScript va mucho más allá del tipado básico. En este artículo exploraremos características avanzadas que transformarán la forma en que escribes código: tipos complejos, genéricos potentes, decoradores, tipos mapeados y utilidades de tipo integradas. Dominar estas características te convertirá en un desarrollador TypeScript de clase mundial.

¿Por qué TypeScript Avanzado importa?

TypeScript es mucho más que un simple verificador de tipos. Con sus características avanzadas, puedes crear APIs type-safe increíblemente expresivas, prevenir clases enteras de bugs, y hacer que tu código sea auto-documentado.

Dato: Los desarrolladores que dominan TypeScript avanzado son capaces de escribir código con 40% menos bugs según estudios de la industria.

Tipos Complejos - Más allá de number, string, boolean

Union Types - Múltiples posibilidades

Un union type permite que una variable sea uno de varios tipos posibles.

type ID = string | number;
type Status = 'pending' | 'approved' | 'rejected';
type Response = { success: true; data: any } | { success: false; error: string };

const userId: ID = 123;        // ✅ Válido
const id2: ID = 'ABC-123';     // ✅ Válido
const id3: ID = true;          // ❌ Error

Discriminated Unions - Tipos seguros y elegantes

Combine union types con un propiedad discriminadora para type-safe handling.

type Success = { status: 'success'; data: string };
type Error = { status: 'error'; message: string };
type Result = Success | Error;

function handleResult(result: Result) {
  if (result.status === 'success') {
    console.log(result.data);    // TypeScript sabe que data existe
  } else {
    console.log(result.message); // TypeScript sabe que message existe
  }
}

Intersection Types - Combinando tipos

Intersection types permiten combinar múltiples tipos en uno.

interface Admin {
  isAdmin: boolean;
  permissions: string[];
}

interface User {
  id: number;
  name: string;
  email: string;
}

type AdminUser = Admin & User;

const adminUser: AdminUser = {
  isAdmin: true,
  permissions: ['read', 'write'],
  id: 1,
  name: 'Juan',
  email: 'juan@example.com'
};

Conditional Types - Lógica en el sistema de tipos

Los conditional types permiten elegir un tipo basado en otro tipo (similares a ternarios).

type IsString = T extends string ? true : false;

type A = IsString<'hello'>;  // tipo true
type B = IsString<123>;      // tipo false

// Ejemplo más práctico
type Flatten = T extends Array ? U : T;

type Str = Flatten;     // string
type Num = Flatten;       // number

Mapped Types - Transformando tipos dinámicamente

Los mapped types permiten crear nuevos tipos basados en propiedades de tipos existentes.

Creando tipos readonly

type User = {
  id: number;
  name: string;
  email: string;
};

type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

// Equivalente a:
// type ReadonlyUser = {
//   readonly id: number;
//   readonly name: string;
//   readonly email: string;
// };

Tipos getters/setters

type Getters = {
  [K in keyof T as `get${Capitalize}`]: () => T[K];
};

interface User {
  name: string;
  age: number;
}

type UserGetters = Getters;
// type UserGetters = {
//   getName: () => string;
//   getAge: () => number;
// };

Genéricos - La Herramienta más Poderosa

Los genéricos permiten escribir componentes, funciones e interfaces reutilizables que trabajen con cualquier tipo manteniendo type-safety.

Genéricos básicos

// Función genérica
function identity(arg: T): T {
  return arg;
}

const result1 = identity('hola');  // string
const result2 = identity(42);      // number
const result3 = identity('inferido');      // TypeScript infiere string

Constraints en genéricos

A veces necesitas restringir qué tipos pueden ser pasados a un genérico.

// Solo tipos con propiedad 'length'
function getLength(arg: T): number {
  return arg.length;
}

getLength('hello');           // ✅ Strings tienen length
getLength([1, 2, 3]);        // ✅ Arrays tienen length
getLength(123);              // ❌ Numbers no tienen length

// Extender otro genérico
function getProperty(obj: T, key: K) {
  return obj[key];
}

const user = { id: 1, name: 'Juan' };
getProperty(user, 'name');   // ✅ 'name' es una propiedad válida
getProperty(user, 'email');  // ❌ 'email' no existe en user

Genéricos en clases

class Stack {
  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];
  }
}

const numberStack = new Stack();
numberStack.push(42);
const value = numberStack.pop();  // number | undefined

Decoradores - Metaprogramación en TypeScript

Los decoradores permiten anotar y modificar clases, propiedades, métodos y parámetros. Son especialmente útiles en frameworks como NestJS.

Decoradores de clase

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class User {
  name: string = 'Juan';
}

const user = new User();
user.newProperty = 'value';  // ❌ Error: no puedes agregar propiedades

Decoradores de método

function deprecated(target: any, property: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) {
    console.warn(`⚠️ ${property} está deprecado`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class API {
  @deprecated
  oldMethod() {
    return 'datos';
  }
}

Decoradores de parámetro

function validate(target: any, propertyKey: string, parameterIndex: number) {
  // Metadata que indica qué parámetro validar
}

class UserService {
  createUser(@validate name: string, email: string) {
    // Validar nombre
  }
}

Utility Types - Herramientas incorporadas de TypeScript

TypeScript incluye muchos tipos de utilidad para manipular tipos de manera común.

Partial - Hace todas las propiedades opcionales

interface User {
  id: number;
  name: string;
  email: string;
}

type PartialUser = Partial;
// Equivalente a:
// {
//   id?: number;
//   name?: string;
//   email?: string;
// }

Required - Hace todas las propiedades requeridas

interface Config {
  apiKey?: string;
  timeout?: number;
}

type RequiredConfig = Required;
// Las propiedades ahora son requeridas

Readonly - Hace todas las propiedades readonly

interface User {
  id: number;
  name: string;
}

type ReadonlyUser = Readonly;
const user: ReadonlyUser = { id: 1, name: 'Juan' };
user.name = 'Pedro';  // ❌ Error: no puedes modificar

Record - Crear tipos con llaves específicas

type Role = 'admin' | 'user' | 'guest';

type Permissions = Record;

const permissions: Permissions = {
  admin: ['read', 'write', 'delete'],
  user: ['read', 'write'],
  guest: ['read']
};

Pick y Omit

interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

// Pick: selecciona propiedades específicas
type UserPreview = Pick;
// { id: number; name: string; }

// Omit: excluye propiedades específicas
type UserPublic = Omit;
// { id: number; name: string; email: string; }

Exclude e Include

type Status = 'pending' | 'approved' | 'rejected' | 'archived';

type ActiveStatus = Exclude;
// 'pending' | 'approved' | 'rejected'

type APIResponse = { data: T } | { error: string };

type SuccessResponse = Extract<
  APIResponse<{ id: number }>,
  { data: any }
>;
// { data: { id: number } }

Patterns avanzados reales

Type-safe Event Emitter

type EventMap = {
  'user:created': { id: number; name: string };
  'user:deleted': { id: number };
  'error': { message: string };
};

class EventEmitter> {
  on(
    event: K,
    callback: (data: Events[K]) => void
  ): void {
    // implementación
  }

  emit(
    event: K,
    data: Events[K]
  ): void {
    // implementación
  }
}

const emitter = new EventEmitter();

emitter.on('user:created', (data) => {
  console.log(data.id, data.name);  // type-safe!
});

emitter.emit('user:created', { id: 1, name: 'Juan' }); // ✅
emitter.emit('user:created', { id: 1 }); // ❌ Error: falta name

Conclusión: TypeScript Avanzado = Código Mejor

Las características avanzadas de TypeScript pueden parecer intimidantes al principio, pero son increíblemente poderosas cuando las dominas. Type-safety, mejor autocompletado del IDE, y documentación auto-generada hacen que valga la pena el esfuerzo de aprender.

Comienza a experimentar con estos conceptos en tus proyectos y verás cómo tu código se vuelve más robusto, mantenible y a prueba de bugs.

Escrito por Andrés Saumet - Especialista en TypeScript y arquitectura de software escalable.

Andres Saumet

Sobre el autor

Andres Saumet

Desarrollador Web & Móvil Full Stack · Colombia

Hay mil desarrolladores que pueden hacer que algo funcione. Yo me obsesiono con hacer que funcione y genere dinero.

Soy Andres Saumet, desarrollador Web y Móvil con foco en rentabilidad. Trabajo con startups, emprendedores y empresas que ya tienen una visión clara y necesitan a alguien que la convierta en un producto digital real — uno que los usuarios quieran usar y que el negocio quiera escalar.

Domino React, Next.js, React Native y Node.js. Pero más allá del stack, entiendo cómo piensan los usuarios, cómo fluye un negocio y qué decisiones técnicas impactan directamente en los ingresos.

Cada línea de código que escribo tiene un propósito: que tu producto web o móvil sea más rápido, más usable y más rentable.

¿Tienes un producto que necesita crecer? Construyámoslo juntos.

Compartir:
Volver al Blog

Todos los derechos reservados Andres Saumet 2026 ©