Skip to content

TypeScript 5.x: las novedades que cambian cómo escribes código

txetxu
Published date:
Edit this post

TypeScript sigue evolucionando a un ritmo frenético. Las versiones 5.x han traído cambios que van más allá de las mejoras de rendimiento: redefinen patrones que llevamos años usando.

Tabla de contenidos

Open Tabla de contenidos

Decoradores estándar (TC39 Stage 3)

Por fin. Después de años con la versión experimental, TypeScript 5.0 adoptó los decoradores estándar de TC39. La sintaxis es similar pero la semántica ha cambiado bastante.

// Decorador de clase — antes (experimental)
@sealed
class OldClass { ... }

// Decorador estándar — TS 5.x
function logged<T extends new (...args: unknown[]) => unknown>(
  target: T,
  _ctx: ClassDecoratorContext,
) {
  return class extends target {
    constructor(...args: unknown[]) {
      super(...args);
      console.log(`[LOG] Instancia de ${target.name} creada`);
    }
  };
}

@logged
class UserService {
  constructor(private db: Database) {}
}decorators.ts

Decoradores de método y acceso

function measure(_target: unknown, ctx: ClassMethodDecoratorContext) {
  const name = String(ctx.name);
  return function (this: unknown, ...args: unknown[]) {
    const start = performance.now();
    const result = (this as Record<string, Function>)[name](...args); 
    const result = Reflect.apply(
      _target as Function,
      this,
      args 
    ); 
    console.log(`${name} tardó ${performance.now() - start}ms`);
    return result;
  };
}

class ReportService {
  @measure
  async generatePDF(id: string) {
    /* ... */
  }
}method-decorator.ts

Parámetros de tipo const

Antes necesitabas usar as const en cada llamada para inferir tuplas literales. Ahora puedes declararlo en el genérico:

// Antes: inferido como string[]
function head<T>(arr: T[]) {
  return arr[0];
}
head(["a", "b"]); // tipo: string

// Ahora: inferido como el literal exacto
function head<const T extends readonly unknown[]>(arr: T) {
  return arr[0];
}
head(["a", "b"] as const); // tipo: "a"
head(["a", "b"]); // tipo: "a"  ← funciona sin as constconst-type-params.ts

Operador satisfies (consolidado)

Introducido en la 4.9 pero ya forma parte del flujo diario. Permite validar que un valor cumple con un tipo sin “ensancharlo” (widening):

type Palette = {
  red: [number, number, number] | string;
  green: [number, number, number] | string;
  blue: [number, number, number] | string;
};

const palette = {
  red: [255, 0, 0],
  green: "#00ff00",
  blue: [0, 0, 255],
} satisfies Palette; 

// Ahora TypeScript sabe que red es una tupla, no un string
palette.red.at(0); // ✓ — antes daba errorsatisfies.ts

Mejoras en la inferencia de infer

// Extraer el tipo de retorno filtrado por restricción
type ReturnIfString<T> = T extends () => infer R extends string
  ? R
  : never;

type A = ReturnIfString<() => "hola">; // "hola"
type B = ReturnIfString<() => number>; // neverinfer-extends.ts

Rendimiento: modo --incremental y --composite

TS 5.x optimizó las compilaciones incrementales. En proyectos grandes la mejora puede ser de hasta 3 veces:

{
  "compilerOptions": {
    "composite": true,
    "incremental": true,
    "tsBuildInfoFile": ".tsbuildinfo",
    "moduleResolution": "bundler"
  }
}tsconfig.json

Consejo: combina composite con referencias de proyecto (references) para monorepos. Cada paquete solo compilará lo que haya cambiado.

Resumen rápido

FuncionalidadVersiónImpacto
Decoradores estándar5.0Alto — reemplaza a los experimentales
Parámetros de tipo const5.0Medio — menos as const
satisfies4.9 / consolidado en 5.xAlto — tipado más expresivo
infer ... extends5.xMedio — tipos condicionales más precisos
Mejora en build incremental5.xAlto en monorepos

Traducido del original (Andrés Ujpán)

Anterior
Agentes de IA autónomos: la nueva forma de construir software en 2026
Siguiente
Rust para desarrolladores JavaScript: el salto que merece la pena dar