Los éxitos discretos de TypeScript 6 y los hábitos de desarrollo en JavaScript de los desarrolladores senior
Descubra las características pasadas por alto de TypeScript 6, como la gestión explícita de recursos y los parámetros de tipo const, además de los modismos en JavaScript en los que confían diariamente los ingenieros senior.
JavaScript moderno y TypeScript siguen evolucionando de maneras que van mucho más allá de las características destacadas y los puntos del changelog. Actualmente son importantes dos aspectos prácticos: las adiciones más discretas y menos difundidas en TypeScript 6, y los patrones habituales de JavaScript que distinguen las solicitudes de integración de nivel avanzado del simple código funcional. Ambos se refieren en realidad a la misma disciplina: conocer bien las herramientas para elegir la adecuada en lugar de la más familiar. Este artículo analiza ambos aspectos, comenzando por las mejoras de TypeScript 6 que pasaron desapercibidas y luego abordando los patrones de JavaScript a los que recurren por defecto los ingenieros experimentados.
Mejoras discretas de TypeScript 6 que vale la pena adoptar
La mayoría de las coberturas sobre TypeScript 6 se detienen en el hecho de que el modo estricto y ES2025 son ahora los valores predeterminados. Eso sí representa un cambio real, pero eclipsa una serie de adiciones menores que eliminan silenciosamente soluciones temporales utilizadas desde hace tiempo. Si solo lees los titulares de tsconfig-default, te has perdido la parte más útil de esta versión.
Limpieza que no necesitas recordar escribir
Una causa común de errores es olvidarse de cerrar una conexión a la base de datos o eliminar un listener. TypeScript 6 aborda esto mediante una gestión explícita de recursos, permitiéndote marcar un valor para que se elimine automáticamente una vez salga del ámbito de validez.
function readUserSession() {
using session = openSession(); // auto-disposed at scope end
const user = session.getUser();
return user.name;
} // session.dispose() called automatically here
Esto elimina la necesidad de bloques try/finally cuya única función era garantizar la limpieza. La adición sintáctica es sencilla, pero los beneficios en términos de fiabilidad son significativos para cualquier cosa que involucre archivos, sockets o conexiones abiertas.
Tipos literales sin necesidad de usar as const en todas partes
Anteriormente, para mantener intactos los tipos literales a través de una función genérica era necesario dispersar as const por todo el código. TypeScript 6 introduce parámetros de tipo const, que preservan automáticamente la inferencia de los valores literales.
function createConfig<const T extends Record<string, unknown>>(config: T) {
return config;
}
const config = createConfig({
env: "production",
features: ["auth", "billing"],
});
// config.env is "production", not string
// config.features is readonly ["auth", "billing"], not string[]
Si desarrollas clientes de API tipados o escribes creadores de acciones para Redux, esto elimina una gran parte del código genérico as const que de otro modo sería necesario.
Reducción adecuada de tipos dentro de switch (true)
Otra mejora bienvenida: las uniones discriminadas ahora pueden reducirse correctamente dentro de una instrucción switch (true), algo que anteriormente obligaba a utilizar cadenas anidadas de if/else para que el compilador comprendiera los tipos.
function area(shape: Shape): number {
switch (true) {
case shape.kind === "circle":
return Math.PI * shape.radius ** 2; // narrowed to Circle
case shape.kind === "rectangle":
return shape.width * shape.height; // narrowed to Rectangle
}
}
Con este cambio, ya no es necesario abandonar switch solo para mantener intacto el estrechamiento de tipos.
Temporal obtiene tipos de primera clase
TypeScript 6 también incluye tipos integrados para la API Temporal, por lo que ya no hay necesidad de lidiar con Date y sus peculiaridades relacionadas con zonas horarias mediante afirmaciones de tipo manuales.
const meetingStart = Temporal.Instant.from("2026-04-06T10:00:00Z");
const localTime = meetingStart.toZonedDateTimeISO("America/Toronto");
Importaciones de subrutas que realmente se resuelven
También se ha corregido un problema menor pero realmente molesto: las importaciones de subrutas internas ahora se resuelven correctamente, sin necesidad de una larga cadena de segmentos de rutas relativas.
import { User } from "#/models/user.js";
// instead of ../../../models/user.js 🙃
Daniel Rosenwasser, gerente de producto de TypeScript, ha descrito a TS6 como un puente deliberado hacia la próxima versión 7 de TypeScript, basada en Go, lo que indica que no se trata de características experimentales temporales, sino de elementos destinados a permanecer. Si su equipo trabaja con un códigobase completo en JavaScript, React o Next.js, adoptar estas prácticas ahora debería reducir las sorpresas cuando llegue TypeScript 7. En general, TypeScript 6 no se trata solo de nuevos valores predeterminados del compilador; también ofrece un manejo más eficiente de los recursos, una inferencia de tipos más precisa y menos soluciones manuales. Probar los parámetros de tipo using y const en su próxima solicitud de integración podría hacerle preguntarse cómo lograba trabajar sin ellos.
Hábitos de JavaScript que diferencian al código avanzado del resto
Conocer las capacidades más recientes de TypeScript es solo la mitad del cuadro. La otra mitad se refiere a cómo se escribe el propio JavaScript día a día. Cuando la solicitud de cambios de un ingeniero senior está mejor estructurada que las de los demás, rara vez se debe a ingenio; se debe a un conjunto consistente de hábitos aplicados sin vacilación.
Cadenas opcionales y unión con valor nulo
En lugar de cadenas como user && user.profile && user.profile.name, el código de nivel senior utiliza cadenas opcionales combinadas con unión con valor nulo.
const displayName = user?.profile?.name ?? 'Guest';
Es conciso, protege contra valores faltantes y no falla cuando se refactorea el código circundante.
Destructuración con valores por defecto
La destructuración de propiedades, respuestas de API y argumentos de funciones —con valores por defecto razonables integrados— es algo natural en este nivel.
function createUser({ name, role = 'member', isActive = true }) {
return { name, role, isActive };
}
Hacer esto documenta la forma esperada de los datos directamente en la firma de la función.
Async/Await en lugar de promesas en cadena
El uso de .then().then().catch() sigue funcionando, pero no escala bien a medida que crece la lógica. Compárelo con una versión de async/await:
async function fetchOrders(userId) {
try {
const res = await fetch(`/api/orders/${userId}`);
if (!res.ok) throw new Error('Failed to fetch orders');
return await res.json();
} catch (err) {
console.error('Order fetch failed:', err);
throw err;
}
}
El resultado se lee de arriba hacia abajo, lo que facilita su depuración y pruebas.
Métodos de array en lugar de bucles manuales
Utilizar map, filter, reduce y find reemplaza a la mayoría de los bucles for escritos a mano.
const activeAdmins = users
.filter((u) => u.isActive && u.role === 'admin')
.map((u) => u.email);
Esto significa menos variables mutables y menos errores por error de desplazamiento en una unidad.
Tipos utilitarios en lugar de interfaces duplicadas
En lugar de redefinir interfaces casi idénticas, el código avanzado en TypeScript utiliza tipos útiles como Partial, Pick y Omit.
type UserFormInput = Pick<User, 'name' | 'email'> & Partial<Pick<User, 'phone'>>;
Eso mantiene una única fuente de verdad, por lo que los cambios en el esquema requieren actualizaciones en menos lugares.
Ganchos y composición en React
Los ganchos personalizados que extraen y encapsulan la lógica aparecen constantemente en bases de código maduras de React.
function useDebouncedValue(value, delay = 300) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
Un gancho como este permite reutilizar la lógica subyacente y probarla de forma independiente de cualquier componente específico.
Gestión estructurada del estado
Para la gestión del estado, muchos equipos avanzados prefieren las slices de Redux Toolkit a los reducers escritos a mano con instrucciones switch, ya que RTK reduce el código genérico y ofrece inmutabilidad de forma gratuita a través de Immer.
Tal como señaló Douglas Crockford, JavaScript está compuesto por “las partes buenas y las partes malas”: la misma flexibilidad que hace poderosa a este lenguaje también genera confusión. Saber en qué partes apoyarse es lo que distingue a los ingenieros seguros de aquellos que aún están aprendiendo.
Un conjunto breve de principios une todo esto: priorizar la legibilidad sobre la ingeniosidad, dejar que el sistema de tipos de TypeScript se encargue de la documentación en lugar de los comentarios, y construir funcionalidades a partir de funciones pequeñas y componibles en lugar de funciones monolíticas grandes.
Lecturas relacionadas
- Proposiciones TC39 en 2026: Decoradores, Temporales y Señales explicados — Una visión práctica de tres propuestas de TC39: los decoradores nativos, la API Temporal y Signals, y su impacto en los desarrolladores de JavaScript y TypeScript full-stack.
- Compartir un esquema Zod entre tu frontend React y backend Node — Aprende cómo un único esquema Zod puede validar formularios de React, respuestas de API, cuerpos de solicitudes de Express y variables de entorno, al tiempo que genera tipos correspondientes en TypeScript.