TypeScript en 2025: Por Qué 38.5% de los Desarrolladores Eligieron y Tú También Deberías
Hola HaWkers, TypeScript está en 38.5% de popularidad según encuestas de 2025, consolidándose como uno de los top 5 lenguajes de programación del mundo. Pero ¿será que es solo hype o hay razones sólidas para adoptar?
En este artículo, vamos a explorar por qué TypeScript dominó el ecosistema JavaScript, cómo comenzar de forma práctica y estrategias de migración para proyectos existentes.
Por Qué TypeScript Venció la Batalla
1. Seguridad de Tipos Previene Bugs Caros
// ❌ JavaScript: Bug solo aparece en producción
function calculateDiscount(price, percentage) {
return price - (price * percentage / 100);
}
// Bug: alguien pasa string por error
calculateDiscount('100', 20); // '100-NaN' = NaN 😱
// ✅ TypeScript: Error detectado en tiempo de desarrollo
function calculateDiscount(price: number, percentage: number): number {
return price - (price * percentage / 100);
}
// Error en tiempo de compilación!
calculateDiscount('100', 20);
// Error: Argument of type 'string' is not assignable to parameter of type 'number'2. IntelliSense y Autocomplete Poderosos
// TypeScript proporciona autocomplete preciso
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
createdAt: Date;
metadata?: {
lastLogin?: Date;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
};
}
function greetUser(user: User) {
// IDE sugiere todas propiedades disponibles
console.log(`Hello, ${user.name}!`);
// Autocomplete en objetos anidados
if (user.metadata?.preferences.theme === 'dark') {
// IDE sabe exactamente lo que está disponible
console.log('Dark mode enabled');
}
// Tipos literales previenen typos
if (user.role === 'admim') { // Error: 'admim' no existe
// ...
}
}3. Refactoring Seguro en Grandes Codebases
// Escenario: Renombrar propiedad en 100 archivos
// Interface original
interface Product {
productName: string;
price: number;
}
// Refactorizar para 'name' en vez de 'productName'
interface Product {
name: string; // TypeScript muestra TODOS los lugares que rompieron
price: number;
}
// Todos los usos son automáticamente identificados
function displayProduct(product: Product) {
return `${product.productName} - $${product.price}`;
// Error: Property 'productName' does not exist on type 'Product'
// Sugerencia: Did you mean 'name'?
}
// En JavaScript: Descubrirías ese bug en producción 💥
TypeScript en la Práctica: Del Básico al Avanzado
Tipos Primitivos y Básicos
// Tipos básicos
let isDone: boolean = false;
let count: number = 42;
let name: string = 'John';
let notSure: any = 4; // ¡Evita usar 'any'!
// Arrays
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ['a', 'b', 'c'];
// Tuplas (arrays con tipos fijos)
let tuple: [string, number] = ['age', 30];
// Enum
enum Status {
Pending = 'PENDING',
Approved = 'APPROVED',
Rejected = 'REJECTED'
}
const orderStatus: Status = Status.Pending;
// Union Types (tipos alternativos)
let id: string | number;
id = '123'; // OK
id = 123; // OK
id = true; // Error
// Literal Types (valores específicos)
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
function makeRequest(url: string, method: HttpMethod) {
// method solo puede ser uno de los valores especificados
}
makeRequest('/api/users', 'GET'); // OK
makeRequest('/api/users', 'PATCH'); // ErrorInterfaces y Type Aliases
// Interface: Define estructura de objetos
interface User {
id: string;
name: string;
email: string;
age?: number; // Opcional
readonly createdAt: Date; // Readonly
}
// Extending interfaces
interface AdminUser extends User {
permissions: string[];
role: 'admin';
}
// Type Alias: Similar a interface, pero más flexible
type Point = {
x: number;
y: number;
};
// Type para union types
type ID = string | number;
// Type para funciones
type GreetFunction = (name: string) => string;
const greet: GreetFunction = (name) => `Hello, ${name}!`;
// Interface vs Type: ¿Cuándo usar?
// Usa Interface para objetos que pueden ser extendidos
// Usa Type para unions, primitivos, tuplas
// Intersection Types (combinar tipos)
type WithTimestamp = {
createdAt: Date;
updatedAt: Date;
};
type UserWithTimestamp = User & WithTimestamp;
const user: UserWithTimestamp = {
id: '1',
name: 'John',
email: 'john@example.com',
createdAt: new Date(),
updatedAt: new Date()
};Generics: Tipos Reutilizables
// Generic simple
function identity<T>(arg: T): T {
return arg;
}
const num = identity<number>(42);
const str = identity<string>('hello');
// Generic con constraints
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): T {
console.log(arg.length); // OK, T tiene length
return arg;
}
logLength('hello'); // OK, string tiene length
logLength([1, 2, 3]); // OK, array tiene length
logLength(42); // Error, number no tiene length
// Generic en interfaces
interface Response<T> {
data: T;
status: number;
message: string;
}
interface User {
id: string;
name: string;
}
const userResponse: Response<User> = {
data: { id: '1', name: 'John' },
status: 200,
message: 'Success'
};
const usersResponse: Response<User[]> = {
data: [
{ id: '1', name: 'John' },
{ id: '2', name: 'Jane' }
],
status: 200,
message: 'Success'
};
// Uso práctico de utility types
interface TodoItem {
id: string;
title: string;
completed: boolean;
createdAt: Date;
}
// Partial: Todos campos opcionales
type TodoUpdate = Partial<TodoItem>;
function updateTodo(id: string, updates: TodoUpdate) {
// Puede pasar solo los campos que quieres actualizar
}
updateTodo('1', { completed: true }); // OK
updateTodo('2', { title: 'New title', completed: false }); // OK
// Pick: Seleccionar solo campos específicos
type TodoSummary = Pick<TodoItem, 'id' | 'title'>;
const summary: TodoSummary = {
id: '1',
title: 'Task'
// completed y createdAt no son necesarios
};
Casos de Uso Avanzados
// 1. Discriminated Unions (Pattern Matching)
type Success<T> = {
type: 'success';
data: T;
};
type Error = {
type: 'error';
error: string;
};
type Result<T> = Success<T> | Error;
function handleResult<T>(result: Result<T>) {
// TypeScript sabe exactamente cuál tipo basado en 'type'
if (result.type === 'success') {
console.log(result.data); // OK, TypeScript sabe que tiene 'data'
} else {
console.log(result.error); // OK, TypeScript sabe que tiene 'error'
}
}
// 2. Conditional Types
type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<string>; // 'yes'
type B = IsString<number>; // 'no'
// 3. Mapped Types
type Optional<T> = {
[K in keyof T]?: T[K];
};
type RequiredUser = {
name: string;
email: string;
age: number;
};
type OptionalUser = Optional<RequiredUser>;
// { name?: string; email?: string; age?: number; }
// 4. Template Literal Types (TypeScript 4.1+)
type HTTPMethod = 'GET' | 'POST' | 'PUT';
type Route = '/users' | '/products' | '/orders';
type APIEndpoint = `${HTTPMethod} ${Route}`;
// 'GET /users' | 'GET /products' | 'GET /orders' |
// 'POST /users' | 'POST /products' | 'POST /orders' |
// 'PUT /users' | 'PUT /products' | 'PUT /orders'
// 5. Type Guards
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function processValue(value: unknown) {
if (isString(value)) {
console.log(value.toUpperCase()); // OK, TypeScript sabe que es string
}
}Migración Gradual de JavaScript para TypeScript
Estrategia de Migración
// 1. Configuración inicial (tsconfig.json)
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"jsx": "react-jsx",
"strict": false, // Comenzar con false, habilitar gradualmente
"allowJs": true, // Permitir archivos .js durante migración
"checkJs": false, // No checar archivos .js inicialmente
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
// 2. Plan de migración
const migrationPlan = {
'Fase 1 - Setup': [
'Instalar TypeScript y tipos',
'Configurar tsconfig.json',
'Renombrar 1 archivo .js → .ts para testar',
'Configurar build pipeline'
],
'Fase 2 - Archivos Nuevos': [
'Todos archivos nuevos en TypeScript',
'Crear types.d.ts para interfaces comunes'
],
'Fase 3 - Migración Gradual': [
'Migrar módulos utilitarios primero',
'Migrar componentes independientes',
'Migrar componentes con dependencias',
'Habilitar strict mode gradualmente'
],
'Fase 4 - Strictness': [
'Habilitar noImplicitAny',
'Habilitar strictNullChecks',
'Habilitar strictFunctionTypes',
'Habilitar strictPropertyInitialization'
]
};
TypeScript con Frameworks Populares
React + TypeScript
import React, { useState, useEffect } from 'react';
// Props tipadas
interface UserCardProps {
user: {
id: string;
name: string;
email: string;
avatar?: string;
};
onEdit?: (userId: string) => void;
onDelete?: (userId: string) => void;
}
// Componente funcional tipado
export function UserCard({ user, onEdit, onDelete }: UserCardProps) {
const [isHovered, setIsHovered] = useState<boolean>(false);
useEffect(() => {
console.log('User card mounted:', user.id);
return () => {
console.log('User card unmounted:', user.id);
};
}, [user.id]);
const handleEdit = () => {
onEdit?.(user.id); // Safe navigation operator
};
return (
<div
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={isHovered ? 'card-hovered' : 'card'}
>
{user.avatar && <img src={user.avatar} alt={user.name} />}
<h3>{user.name}</h3>
<p>{user.email}</p>
<button onClick={handleEdit}>Edit</button>
{onDelete && (
<button onClick={() => onDelete(user.id)}>Delete</button>
)}
</div>
);
}
// Hooks customizados tipados
function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let cancelled = false;
async function fetchUser() {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
if (!cancelled) {
setUser(data);
}
} catch (err) {
if (!cancelled) {
setError(err as Error);
}
} finally {
if (!cancelled) {
setLoading(false);
}
}
}
fetchUser();
return () => {
cancelled = true;
};
}, [userId]);
return { user, loading, error };
}Next.js + TypeScript
// app/page.tsx (App Router)
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Home Page',
description: 'Welcome to my site'
};
interface HomePageProps {
searchParams: { [key: string]: string | string[] | undefined };
}
export default async function HomePage({ searchParams }: HomePageProps) {
// Server component tipado
const data = await fetchData();
return (
<div>
<h1>Welcome</h1>
<DataDisplay data={data} />
</div>
);
}
// API Route tipada
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
interface UserPayload {
name: string;
email: string;
}
export async function POST(request: NextRequest) {
try {
const body: UserPayload = await request.json();
// Validación
if (!body.name || !body.email) {
return NextResponse.json(
{ error: 'Missing required fields' },
{ status: 400 }
);
}
// Crear usuario
const user = await createUser(body);
return NextResponse.json(user, { status: 201 });
} catch (error) {
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
Conclusión: ¿Vale la Pena Invertir en TypeScript?
Sí, absolutamente. TypeScript no es más una tendencia — es el nuevo estándar para JavaScript profesional en 2025.
Beneficios concretos:
- Menos bugs: Errores detectados antes de producción
- Mejor DX: Autocomplete y refactoring seguros
- Código más mantenible: Documentación viva via tipos
- Carrera: 68% de las vacantes exigen TypeScript
Si quieres dominar JavaScript y TypeScript de forma estructurada, recomiendo que des una mirada a otro artículo: Programación Funcional en JavaScript: Entendiendo Higher-Order Functions donde vas a descubrir patrones que funcionan perfectamente con TypeScript.
¡Vamos a por ello! 🦅
📚 ¿Quieres Profundizar Tus Conocimientos en JavaScript?
Este artículo cubrió TypeScript, pero dominar JavaScript sólido es la base para todo.
Desarrolladores que invierten en conocimiento estructurado tienden a tener más oportunidades en el mercado.
Material de Estudio Completo
Si quieres dominar JavaScript del básico al avanzado, preparé una guía completa:
Opciones de inversión:
- $9.90 USD (pago único)
💡 Material actualizado con las mejores prácticas del mercado

