Por qué TypeScript Avanzado Importa en 2026
TypeScript ya no es opcional en proyectos serios. Con más del 78% de los proyectos JavaScript profesionales usando TypeScript según la encuesta State of JS 2025, la pregunta ya no es si usarlo, sino qué tan bien lo estás usando.
Estos 10 tips están basados en code reviews reales de proyectos que hemos auditado. Son los patrones que más frecuentemente encontramos infrautilizados o mal aplicados, y que tienen el mayor impacto en la mantenibilidad y robustez del código.
1. Usa Discriminated Unions en lugar de Booleans para Estado
Un patrón muy común pero problemático es representar estados con múltiples booleans: isLoading, isError, isSuccess. El problema es que crean combinaciones de estado imposibles pero que TypeScript no detecta.
La solución es usar un discriminated union con un campo discriminador literal:
- Estado
idle: estado inicial, sin datos ni error - Estado
loading: request en curso - Estado
success: datos disponibles, TypeScript sabe quedataexiste - Estado
error: error disponible, TypeScript sabe queerrorexiste
Con este patrón, cuando haces un switch/case sobre el campo status, TypeScript estrecha el tipo automáticamente en cada rama y te obliga a manejar todos los casos posibles.
2. Template Literal Types para APIs Type-Safe
Los Template Literal Types permiten construir tipos de string con estructura definida, lo que es ideal para crear APIs de rutas, event names o identificadores con formato predecible.
Por ejemplo, puedes definir tipos como EventName que solo acepte strings con el formato "on" + NombreDeEvento, o rutas de API que solo acepten paths válidos de tu aplicación. TypeScript verifica en tiempo de compilación que estás usando el formato correcto.
3. satisfies Operator — Inferencia sin Perder Type Safety
El operador satisfies (introducido en TS 4.9) es uno de los más subutilizados. Permite que TypeScript valide que un valor cumple con un tipo, pero sin ampliar el tipo inferido al tipo declarado.
La diferencia práctica: cuando usas as const satisfies Type, TypeScript sabe exactamente qué valor tiene cada propiedad, no solo que es del tipo correcto. Esto habilita autocompletado preciso y verificación de exhaustividad en switches.
4. Branded Types para Primitivos Distintos
¿Cuántas veces has pasado un userId donde esperaba un postId, ambos siendo string? Los Branded Types resuelven esto creando tipos nominales sobre primitivos.
La técnica consiste en intersectar un string o number con un objeto que tiene una propiedad simbólica única. Así, UserId y PostId son incompatibles aunque ambos sean strings en runtime. TypeScript rechazará en compilación cualquier mezcla accidental.
5. infer en Conditional Types para Extracción de Tipos
La palabra clave infer dentro de conditional types permite extraer partes de un tipo complejo. Es la base de muchos utility types de la librería estándar y de librerías como tRPC o Zod.
- Extraer el tipo de retorno de una función asíncrona
- Obtener el tipo del primer argumento de cualquier función
- Extraer el tipo de elemento de un array, incluso anidado
- Inferir el tipo de props de un componente React a partir del componente mismo
6. Exhaustiveness Checking con never
Una de las características más poderosas de TypeScript es verificar en tiempo de compilación que has manejado todos los casos de un union type. El truco es crear una función assertNever(x: never) y llamarla en el default de un switch.
Si añades un nuevo valor al union y olvidas manejar ese caso en el switch, TypeScript lanzará un error de compilación porque el valor llegará al assertNever sin haber sido narrowed a never.
7. Utility Types Combinados para Transformaciones Complejas
Los utility types de TypeScript son más poderosos cuando se combinan. Algunos patrones útiles:
- DeepReadonly: combina
Readonlycon mapped types recursivos para inmutabilidad profunda - PickByValue: seleccionar propiedades de un objeto según el tipo de su valor
- RequiredByKey: hacer obligatorias solo ciertas propiedades opcionales
- MergeDeep: mergear dos tipos de objetos con soporte de tipos anidados
8. Function Overloads para APIs con Múltiples Firmas
Cuando una función puede recibir diferentes tipos de argumentos y retornar diferentes tipos según esos argumentos, las function overloads comunican ese contrato de manera precisa al caller.
La clave es definir las firmas de overload antes de la implementación. TypeScript usará las firmas para inferencia, no la implementación. Esto permite que el caller obtenga el tipo de retorno correcto según los argumentos que pase.
9. Module Augmentation para Extender Tipos de Terceros
Cuando una librería de terceros no tiene los tipos que necesitas, o cuando necesitas añadir propiedades a un tipo existente (como extender la sesión de NextAuth), el module augmentation es la forma correcta de hacerlo sin modificar node_modules.
Crea un archivo .d.ts y usa declare module 'nombre-del-modulo' para extender las definiciones de tipo existentes. TypeScript fusionará automáticamente tu declaración con la original.
10. const Assertions y as const satisfies
El modificador as const convierte un literal en su tipo más específico posible: arrays en tuplas de solo lectura, strings en sus tipos literales, numbers en sus valores exactos. Combinado con satisfies, obtienes validación de tipo con inferencia precisa.
Este patrón es especialmente útil para configuraciones, paletas de colores, listas de opciones y cualquier dato que sea constante en runtime pero que quieras que TypeScript trate con la mayor precisión posible.
El Camino Hacia un Codebase TypeScript Maduro
Adoptar estos patrones gradualmente — empezando por los que más se aplican a tu proyecto actual — tiene un impacto compuesto en la calidad del código. Cada tipo bien definido reduce la superficie de bugs posibles y hace el código auto-documentado.
En Start By Global, todos nuestros proyectos de desarrollo web usan TypeScript estricto desde el inicio. Si quieres revisar la calidad de tu codebase o arrancar un proyecto nuevo con las mejores prácticas, conversemos.