
La respuesta más adecuada desde luego sería: ¿Y por qué no?.
No es de extrañar que cada nuevo producto introducido en el mercado del desarrollo de software sea puesto a prueba por toda la comunidad y posteriormente criticado, positiva o negativamente. Al final eso hace que el resto termine posicionándose como defensor o detractor de la herramienta.
Dentro de la comunidad JavaScript, TypeScript no iba a ser menos. Pero, en el fondo, lo que cualquiera quiere saber es algo mucho más simple: ¿es bueno o malo?, ¿qué me aporta?, ¿qué me resta? La respuesta depende de las necesidades de cada proyecto y de si esta herramienta resuelve un problema real o solo añade complejidad innecesaria.
¿Qué es TypeScript?
Hay quien defiende que TypeScript es un lenguaje de programación. Desde mi punto de vista, esa definición se queda corta o directamente no es exacta, porque el código sigue necesitando transpilarse a JavaScript para ejecutarse. Me parece más acertada la definición de sus propios creadores: un superset de JavaScript que permite, entre otras cosas, añadir tipado.
Esto gana todavía más relevancia si pensamos en el contexto del ecosistema. Con la llegada de Deno, y con el propio Ryan Dahl reconociendo que no haber apostado por un lenguaje tipado en Node.js fue un error, TypeScript se consolidó todavía más como una opción seria para construir software mantenible.
¿Por qué surge?
Quienes llevan tiempo trabajando en proyectos grandes, con muchos desarrolladores y mucho JavaScript, saben que la ausencia de tipado y la enorme flexibilidad para definir objetos es un arma de doble filo.
Por una parte nos da libertad. Por otra, nos obliga a confiar demasiado en que todos usamos esa libertad con responsabilidad. Un simple error tipográfico, una propiedad con un nombre distinto al esperado o una estructura implícita mal entendida puede introducir fallos difíciles de detectar.
TypeScript aparece precisamente para responder a eso. Cuando trabajamos con datos modelados, sabemos qué atributos tiene una clase o un objeto, queda expresado en el código y no tenemos que especular sobre su composición.
¿Dónde usarlo?
Puede usarse tanto en backend como en frontend. Y eso es importante porque el valor de TypeScript no es un capricho, sino una respuesta a una necesidad distinta según el contexto.
En backend es especialmente útil porque trabajamos en la capa más abstracta del software: dominio, servicios, contratos, integraciones. Ahí el tipado ayuda a modelar reglas, forzar compromisos de diseño y hacer más explícitas las dependencias entre piezas del sistema.
En frontend se suele escuchar un argumento habitual: el código generado por la transpilación puede ser más pesado que si se hubiese escrito a mano en JavaScript. Es una observación legítima, pero conviene ponerla en contexto. Desde mi punto de vista, descargar algunos kilobytes extra es un coste pequeño si a cambio se gana productividad, semántica y protección frente a errores que de otra forma tendríamos que validar manualmente.
¿Quién lo mantiene?
La comunidad que hay detrás de una herramienta importa mucho. Sirve para medir soporte, evolución y confianza en el futuro del proyecto.
En el caso de TypeScript, el principal impulsor es Microsoft, pero no está solo. Frameworks y comunidades como Angular, Ionic o Vue también lo han abrazado. A eso se suma una comunidad enorme que mantiene tipos para miles de librerías del ecosistema JavaScript.
Un ejemplo claro es DefinitelyTyped, un macrorepositorio donde se alojan muchas de las definiciones de tipos más utilizadas.
¿Alternativas?
TypeScript no es la única herramienta con esta intención. Existen otras como PureScript o ReasonML. No es el objetivo de este artículo compararlas en detalle, pero sí recordar que hay más de una forma de afrontar el problema del tipado y la semántica en aplicaciones JavaScript.
¿Qué nos aporta?
Uno de los beneficios más importantes, y a la vez menos mencionados, es la semántica. Cuando te centras en controlar el dominio de una aplicación, la semántica del código es esencial. El tipado ayuda mucho a reforzarla.
Veamos un ejemplo simplificado:
const character = findCharacterById(id);
character.run();
En ese ejemplo estamos dando demasiadas cosas por supuestas:
- Que
ides unstringválido. - Que
findCharacterByIddevuelve realmente un personaje. - Que ese personaje implementa
run().
Eso funciona mientras vivimos en el happy path, pero deja demasiados huecos abiertos para el resto de casos.
Ahora pensemos en una versión más explícita:
type CharacterId = string & { readonly brand: unique symbol };
interface Character {
id: CharacterId;
}
interface Hero extends Character {
saveTheDay(): void;
}
function findHeroById(id: CharacterId): Hero {
// ...
}
Aquí el identificador deja de ser “cualquier string”, el contrato del método obliga a usar el tipo correcto y el resultado expresa mejor la intención del dominio. Cuando agregamos semántica, reducimos las suposiciones y evitamos comprobaciones manuales innecesarias.
¿Qué nos quita?
Por supuesto, trabajar con tipos también tiene costes. Reduce cierta flexibilidad, obliga a definir interfaces y a adaptar esos contratos a medida que evoluciona el diseño. Eso puede ralentizar el desarrollo, especialmente al principio.
Un caso habitual aparece cuando queremos envolver children en un componente de React para construir algo como un carrusel:
type CarouselProps = {
children: React.ReactElement[];
};
function Carousel({ children }: CarouselProps) {
return <div>{children.map((child) => child)}</div>;
}
En JavaScript probablemente accederíamos a this.props.children y usaríamos map sin demasiadas preguntas. En TypeScript, en cambio, los tipos de React nos obligan a especificar qué esperamos realmente. Eso añade trabajo, sí, pero también aclara el contrato del componente.
Malos usos: any
Uno de los tipos más “divertidos” de TypeScript es any, precisamente porque admite cualquier cosa.
Puede ser útil en una fase inicial del desarrollo, cuando quieres avanzar rápido y todavía no conoces bien el contrato de una librería o una integración. El problema aparece cuando ese any se queda para siempre. Entonces perdemos gran parte del valor de TypeScript y solo mantenemos el coste.
Malos usos: propiedades opcionales
Algo parecido ocurre con las propiedades opcionales:
type Exercise = {
name?: string;
warning?: string;
};
Que algo pueda ser opcional no significa que debamos hacer opcional todo el modelo. Si exageramos ese patrón volvemos al mismo problema que queríamos evitar: no tener certeza de qué existe y qué no.
Conclusión
Desde mi punto de vista, TypeScript tiene una curva de aprendizaje ligera y puede producir un código transpìlado menos óptimo que una implementación manual muy afinada en JavaScript. Pero, en la mayoría de los casos, compensa con claridad, semántica, mantenibilidad y detección temprana de errores.
Eso no significa que haya que usarlo siempre. Si el proyecto tiene una vida muy corta o solo estamos haciendo un spike, quizá sea sobreingeniería. El valor real está en saber cuándo una herramienta ayuda y cuándo estorba.
No se trata de estar en contra de JavaScript plano, ni de pensar que quien no use TypeScript está equivocado. Se trata de elegir bien según el contexto.