TypeScript: El estándar del desarrollo web moderno
En agosto de 2025, GitHub publicó algo que muchos veíamos venir pero que igual pegó fuerte: TypeScript superó a JavaScript y a Python como el lenguaje más usado en la plataforma. No fue de un día para otro. Fue la suma de varios años de crecimiento sostenido, adopción masiva en empresas grandes, y un ecosistema que se volvió difícil de ignorar.
GitHub Octoverse 2025: el dato
Un aumento del 66% año tras año en contribuidores. Empresas como Microsoft, Google, Meta y Netflix usándolo como estándar para proyectos críticos. Más de 5 millones de paquetes en npm con soporte de tipos. Casi un millón de repositorios públicos escritos en TypeScript.
Cuando un lenguaje llega a esa masa crítica, deja de ser una preferencia personal y se convierte en infraestructura. Los nuevos proyectos arrancan en TypeScript por defecto. Los equipos que migran rara vez vuelven atrás.
TypeScript 7.0: el compilador reescrito en Go
Si hubo un momento que definió 2025 para TypeScript, fue el lanzamiento de TypeScript 7.0, conocido como Project Corsa. Reescribieron el compilador principal en Go, y los resultados son brutales.
Proyectos grandes que tardaban 5 minutos en compilar ahora lo hacen en 30 segundos. Eso es un 10x en velocidad de compilación. El consumo de memoria baja hasta 60% durante la compilación. El soporte para monorepos mejoró significativamente. Y lo mejor: sin cambios en la sintaxis ni en el comportamiento de tipos. Tu código sigue siendo el mismo, solo que compila mucho más rápido.
// TypeScript 7.0 compila este código 10x más rápido
interface Usuario {
id: string;
nombre: string;
email: string;
rol: 'admin' | 'usuario' | 'invitado';
}
function procesarUsuario(usuario: Usuario): { mensaje: string } {
return { mensaje: `Bienvenido, ${usuario.nombre}` };
}Utilidades de tipos que uso a diario
El sistema de tipos de TypeScript tiene utilidades que vale la pena dominar. Estas son las que más uso.
Partial para updates
Partial es perfecto para operaciones tipo PATCH donde solo actualizas algunos campos:
interface Producto {
id: string;
nombre: string;
precio: number;
descripcion: string;
stock: number;
}
function actualizarProducto(
id: string,
cambios: Partial<Producto>
): Producto {
const producto = obtenerProductoPorId(id);
return { ...producto, ...cambios };
}
// Uso: solo actualizamos el precio
actualizarProducto('prod-123', { precio: 29.99 });Pick y Omit para no filtrar datos sensibles
Cuando necesitas exponer solo ciertos campos de una entidad, Pick y Omit son tus amigos:
interface UsuarioCompleto {
id: string;
nombre: string;
email: string;
password: string;
createdAt: Date;
updatedAt: Date;
}
// Pick: seleccionamos campos específicos
type UsuarioPublico = Pick<UsuarioCompleto, 'id' | 'nombre' | 'email'>;
// Omit: excluimos campos sensibles
type UsuarioSinPassword = Omit<UsuarioCompleto, 'password'>;
function obtenerPerfilPublico(id: string): UsuarioPublico {
return obtenerUsuarioCompleto(id);
}La diferencia entre ambos es de gusto. Pick cuando sabes qué quieres incluir, Omit cuando sabes qué quieres excluir. Yo prefiero Pick para APIs públicas porque es más explícito sobre lo que expone.
TypeScript e IA: mejor juntos
El contexto de tipos hace que los LLMs generen código mucho mejor. Datos concretos: GPT-4 y Claude generan código TypeScript con 94% menos errores de compilación que JavaScript equivalente. GitHub Copilot y Cursor dan sugerencias más precisas porque los tipos les dan contexto. Y herramientas como Prettier y ESLint con TypeScript permiten refactorizaciones mucho más seguras.
// Ejemplo de cómo los tipos ayudan a los LLMs
type EstadoPedido = 'pendiente' | 'procesando' | 'enviado' | 'entregado';
interface Pedido {
id: string;
estado: EstadoPedido;
items: Array<{ nombre: string; cantidad: number }>;
}
function avanzarEstadoPedido(pedido: Pedido): Pedido {
// Un LLM puede inferir correctamente los posibles estados siguientes
const transiciones: Record<EstadoPedido, EstadoPedido> = {
pendiente: 'procesando',
procesando: 'enviado',
enviado: 'entregado',
entregado: 'entregado',
};
return {
...pedido,
estado: transiciones[pedido.estado],
};
}Un LLM viendo ese tipo EstadoPedido entiende exactamente qué valores son válidos. No inventa estados. No se equivoca de string. Ese es el tipo de contexto que marca la diferencia.
Por qué TypeScript y no JavaScript
El argumento se reduce a una cosa: detectar errores antes de que lleguen a producción.
// JavaScript: error solo se descubre en tiempo de ejecución
function calcularArea(ancho, alto) {
return ancho * alto;
}
calcularArea("10", 20); // Retorna "200" (concatenación de strings)
// TypeScript: error detectado en compilación
function calcularArea(ancho: number, alto: number): number {
return ancho * alto;
}
calcularArea("10", 20); // Error: Type 'string' is not assignable to parameter of type 'number'Ese ejemplo es trivial, pero escala. En código real, con estructuras de datos complejas, la diferencia entre "te enteras en compilación" y "te enteras cuando un usuario reporta el bug" es enorme.
Los tipos también funcionan como documentación viva. El autocompletado de VS Code es más preciso. Ir a definición y buscar referencias funcionan mejor. Y cuando alguien nuevo se integra al equipo, entender el código es mucho más rápido cuando los tipos explican qué recibe cada función y qué devuelve.
En los frameworks que usamos todos los días
React
interface Props {
titulo: string;
onClic?: () => void;
children?: React.ReactNode;
}
function Boton({ titulo, onClic, children }: Props) {
return (
<button onClick={onClic} className="px-4 py-2 bg-blue-500 rounded">
{titulo}
{children}
</button>
);
}Next.js
import { GetServerSideProps } from 'next';
interface PageProps {
usuario: {
id: string;
nombre: string;
};
}
export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
const usuario = await obtenerUsuario();
return { props: { usuario } };
};
export default function Pagina({ usuario }: PageProps) {
return <div>Bienvenido, {usuario.nombre}</div>;
}Vue 3
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'Contador',
setup() {
const contador = ref<number>(0);
const incrementar = () => contador.value++;
return { contador, incrementar };
},
});Cosas que dejo de hacer en 2025
Dejar de usar any
any apaga el compilador. Si necesitas flexibilidad, usa unknown y valida:
// ❌ Evitar any
function procesarDato(dato: any) {
return dato.valor;
}
// ✅ Usar unknown con validación
function procesarDato(dato: unknown) {
if (typeof dato === 'object' && dato !== null && 'valor' in dato) {
return (dato as { valor: string }).valor;
}
throw new Error('Formato de dato inválido');
}Usar tipos discriminados
Los tipos discriminados le dan a TypeScript suficiente información para hacer narrowing automáticamente:
interface Success {
status: 'success';
data: string;
}
interface Error {
status: 'error';
message: string;
}
type Resultado = Success | Error;
function manejarResultado(resultado: Resultado) {
// TypeScript sabe exactamente qué propiedades existen
if (resultado.status === 'success') {
console.log(resultado.data);
} else {
console.log(resultado.message);
}
}Si vienes de lenguajes como Rust o Swift, esto te resulta familiar. Es la forma más limpia de modelar resultados que pueden ser una cosa u otra.
Migrar a TypeScript: el cálculo
Si tu equipo evalúa migrar, esto es lo que pesé cuando lo hice. La mayoría de los desarrolladores JavaScript se adaptan en 2 a 4 semanas. TypeScript es un superconjunto de JavaScript, así que puedes migrar gradualmente, archivo por archivo. No necesitas un big bang.
El impacto en el negocio es real. Los errores de tipo que se detectan antes del despliegue reducen los bugs en producción hasta un 60%. El autocompletado y la navegación de código mejorada aumentan la productividad del equipo entre 15% y 25%. El tiempo de depuración baja hasta 40%. Y los tipos funcionan como documentación viva del código, lo que facilita la onboarding de gente nueva.
Cierre
TypeScript en 2025 no es una preferencia ni una moda. Es el estándar. Si todavía no lo usas, te estás perdiendo detección de errores en compilación, mejor experiencia en el IDE, interoperabilidad natural con herramientas de IA, y un compilador que con la versión 7.0 es ridículamente rápido.
El costo de entrada es bajo. El costo de no adoptarlo sube cada mes.