Antes de lanzarte a migrar, conviene saber dónde se va a concentrar el esfuerzo real. La mayor parte del trabajo en una migración de este tipo suele estar en un único punto: el manejo de errores en bloques try...catch, porque el comportamiento por defecto se vuelve más estricto. El resto de novedades son mejoras que se adoptan después, con calma, una vez que el código compila sin errores.
El cambio que rompe más código: catch ahora es unknown
El compilador trata ahora la variable capturada en catch (e) como unknown en vez de any. Esto obliga a comprobar el tipo antes de acceder a sus propiedades, lo cual evita errores en tiempo de ejecución, pero rompe cualquier código que asumiera una forma concreta del error sin comprobarla:
// Código antiguo (ahora da error)
try {
// ...
} catch (e) {
console.error(e.message); // Error: 'e' es 'unknown'
}
// Código correcto en TS 5.9+
try {
// ...
} catch (e) {
if (e instanceof Error) {
console.error(e.message);
} else {
console.error(`Error: ${String(e)}`);
}
}
Si tu base de código tiene muchos bloques try...catch, este es, con diferencia, el punto que más tiempo va a llevar durante la migración.
Novedades para adoptar después de migrar
Narrowing más inteligente en switch (true): el compilador ahora estrecha tipos correctamente incluso con condiciones múltiples dentro de esta estructura.
function processValue(val: string | number) {
switch (true) {
case typeof val === "string":
console.log(val.toUpperCase());
break;
case typeof val === "number":
console.log(val.toFixed(2));
break;
}
}
Mejor inferencia de contexto en decoradores: mayor precisión al tipar los argumentos de decoradores de clases y métodos.
function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Método registrado: ${propertyKey}`);
}
class Service {
@LogMethod
getData(id: number) {
return `Datos para ${id}`;
}
}
Sintaxis using await: gestión automática y segura de recursos asíncronos que necesitan limpieza, implementando AsyncDisposable.
async function example() {
await using db = await getDbConnection();
const result = await db.query("...");
return result;
}
Otro cambio de ruptura a vigilar: la API interna del compilador
Si tu código usa directamente el API del compilador (ts.factory), es posible que necesites actualizar el nombre de algunas funciones:
// Antes (obsoleto)
ts.createPropertyAccess(obj, "prop");
// Después
ts.factory.createPropertyAccessExpression(obj, "prop");
Configuración recomendada en tsconfig.json
"target": "ES2022"o superior — es el mínimo necesario para usarusing await."moduleResolution": "bundler"— recomendado para entornos modernos con bundlers como Vite o esbuild."strict": true— habilitauseUnknownInCatchVariables, el cambio de comportamiento más importante de esta versión."noUncheckedIndexedAccess": true— añade seguridad de tipos extra al acceder a arrays por índice.
Plan de migración recomendado
- Sube la versión de TypeScript y compila: la mayoría de errores nuevos vendrán de los bloques
catch. - Corrige esos bloques uno a uno, añadiendo comprobaciones de tipo (
instanceof Errores el caso más común). - Si usas el API interno del compilador en herramientas propias, actualiza las llamadas a
ts.factory. - Ejecuta la suite de tests completa antes de dar la migración por cerrada.
- Solo después de esto, explora las novedades de lenguaje (narrowing en switch, decoradores,
using await) donde aporten valor real, sin prisa por adoptarlas todas de golpe.






Comentarios (0)
Deja un comentario
No hay comentarios aún. ¡Sé el primero en comentar!