TypeScript es JavaScript con un sistema de tipos estático encima. Todo programa JavaScript es sintaxis TypeScript válida; TypeScript añade anotaciones de tipo, un compilador que las comprueba antes de ejecutar el código y un paso de build que las vuelve a quitar. En tiempo de ejecución solo hay JavaScript, así que la diferencia está por completo en lo que descubres antes de publicar.
En JavaScript, la misma función es este código sin type Product = ..., : Product[] ni : number. Los tipos añaden información para el compilador y el editor; no cambian lo que hace el programa.
TypeScript vs JavaScript de un vistazo
| JavaScript | TypeScript | |
|---|---|---|
| Sistema de tipos | Dinámico: los tipos pertenecen a los valores y solo se conocen en tiempo de ejecución | Estático: los tipos se declaran o se infieren y se comprueban al compilar |
| Cuándo aparecen los errores de tipo | Cuando se ejecuta la línea (undefined, NaN, TypeError) | En el editor mientras escribes, y al compilar |
| Dónde se ejecuta | Navegadores, Node.js, Deno, Bun, directamente | En los mismos sitios, después de quitar los tipos |
| Paso de build | No hace falta | tsc o un bundler, o un runtime que quita los tipos por sí mismo |
| Archivos | .js, .mjs, .cjs | .ts, .mts, .cts, .tsx, más las declaraciones de tipos .d.ts |
| Velocidad en ejecución | Referencia | Idéntica: la salida es JavaScript |
| Soporte del editor | Autocompletado a partir de tipos inferidos y de los tipos de las librerías, que pueden estar incompletos | Autocompletado, renombrar y "buscar todas las referencias" a partir de los tipos declarados |
| Curva de aprendizaje | Más baja | JavaScript más el sistema de tipos |
| Estándar | ECMAScript, de TC39 | Un proyecto de código abierto de Microsoft que sigue a ECMAScript |
El mismo código en los dos lenguajes
Aquí tienes una función en JavaScript. Nada en ella dice qué forma debe tener user:
function greeting(user) {
return `Hello, ${user.firstName} ${user.lastName}`;
}
greeting({ firstname: "Ada", lastName: "Lovelace" });
// "Hello, undefined Lovelace", no error anywhere
La versión en TypeScript declara la forma una vez, y la errata se detecta antes de ejecutar el código:
interface User {
firstName: string;
lastName: string;
}
function greeting(user: User): string {
return `Hello, ${user.firstName} ${user.lastName}`;
}
greeting({ firstname: "Ada", lastName: "Lovelace" });
// error TS2561: Object literal may only specify known properties,
// but 'firstname' does not exist in type 'User'. Did you mean to write 'firstName'?
Las anotaciones son toda la diferencia de sintaxis. TypeScript también añade algunas declaraciones propias (interface, type, enum, genéricos como Array<string>, modificadores de acceso como private), pero las sentencias, los operadores y los objetos integrados son los de JavaScript.
Qué detecta TypeScript y JavaScript no
JavaScript convierte los tipos en silencio. Este error es habitual con valores que vienen de campos de formulario, que siempre son strings. Ejecútalo para ver qué dice el compilador:
index.ts(7,17): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'number[]'.
Type 'string' is not assignable to type 'number'.
En JavaScript esto se ejecuta e imprime 010205, porque 0 + "10" es una concatenación de strings. TypeScript se niega a compilar hasta que conviertas los strings, por ejemplo con fromForm.map(Number).
La otra gran categoría son los valores que pueden faltar. Array.prototype.find devuelve undefined cuando nada coincide, y TypeScript te obliga a tratar ese caso:
index.ts(8,13): error TS18048: 'user' is possibly 'undefined'.
La versión en JavaScript puro falla en tiempo de ejecución con TypeError: Cannot read properties of undefined (reading 'name'). La solución en TypeScript es tratar el caso que señaló el compilador:
Salida:
GRACE
no user with id 3
Lo que TypeScript no detecta: los errores de lógica (una fórmula equivocada tiene el tipo correcto) y todo lo relacionado con datos que entran en el programa en tiempo de ejecución. Una respuesta de una API tipada como User solo es tan correcta como el servidor que la envió, porque los tipos desaparecen cuando el código se ejecuta. Comprueba esos datos con código de tiempo de ejecución.
Usar librerías JavaScript en TypeScript
Cualquier paquete de npm funciona desde TypeScript, porque la salida es JavaScript de todos modos. Los tipos de un paquete vienen de uno de estos tres sitios:
- El paquete incluye sus propios archivos
.d.ts. La mayoría de los paquetes mantenidos lo hacen, y no instalas nada más. - Un paquete
@typesaparte del proyecto comunitario DefinitelyTyped:npm install --save-dev @types/lodashañade los tipos delodash. - De ningún sitio. Entonces, con
strictactivado, el propio import es un error:
error TS7016: Could not find a declaration file for module 'lodash'. '/project/node_modules/lodash/lodash.js' implicitly has an 'any' type.
Try `npm i --save-dev @types/lodash` if it exists or add a new declaration (.d.ts) file containing `declare module 'lodash';`
La solución es instalar el paquete @types si existe, o describir tú mismo el módulo en un archivo .d.ts; la página de archivos de declaración explica cómo.
El paso de build
Los navegadores y Node.js no comprueban tipos, así que TypeScript necesita un paso entre tu código fuente y el código que se ejecuta. Hay tres configuraciones habituales:
tsclo compila todo. Comprueba los tipos y escribe archivos.js, normalmente en una carpetadist. Es sencillo y es lo estándar para librerías.- Un bundler o servidor de desarrollo quita los tipos, y
tsc --noEmitlos comprueba. Vite y esbuild eliminan los tipos sin comprobarlos, lo que mantiene rápidas las recargas; el editor y un paso de CI ejecutan el comprobador de tipos. - El runtime quita los tipos. Las versiones actuales de Node.js, Deno y Bun ejecutan archivos
.tsdirectamente. Ninguno comprueba tipos al ejecutar, así quetsc --noEmit(odeno check) sigue siendo la forma de encontrar errores de tipo.
JavaScript no necesita nada de esto, y esa es su mayor ventaja práctica para scripts pequeños. El coste del paso de TypeScript es sobre todo la configuración, un tsconfig.json y una dependencia de desarrollo typescript, y el tiempo de compilación; el compilador nativo de TypeScript 7 redujo ese tiempo unas diez veces en proyectos grandes.
Curva de aprendizaje
Todo lo que sabes de JavaScript te sirve, porque el runtime de TypeScript es JavaScript. Lo nuevo es el sistema de tipos, y llega por capas:
- Anotaciones en variables, parámetros y valores de retorno (
: string,: number[]). - Tipos de objeto con
interfaceytype, propiedades opcionales, uniones comostring | number. - Estrechamiento: comprobar un valor con
typeof,ino===para que el compilador sepa en qué caso estás. - Genéricos, utility types como
Partial<T>yPick<T, K>, y tipos avanzados para autores de librerías.
Las dos primeras capas cubren la mayor parte del código de una aplicación. Gran parte de los tipos se infiere, así que mucho código TypeScript parece JavaScript con anotaciones solo en las firmas de las funciones.
Cuándo elegir TypeScript o JavaScript
¿Es TypeScript mejor que JavaScript? Para código que mantienen varias personas o que vive años, normalmente sí, y la industria ha ido en esa dirección: según el recuento de contribuidores mensuales de GitHub, TypeScript superó a JavaScript y a Python en agosto de 2025 y se convirtió en el lenguaje más usado en GitHub. Para scripts pequeños, JavaScript puro suele ser la mejor herramienta.
Elige TypeScript cuando:
- Trabaja más de una persona en el código, o se va a mantener durante meses o años.
- El código es lo bastante grande como para no poder tener en la cabeza todas las firmas de las funciones.
- Refactorizas a menudo: renombrar una propiedad actualiza cada uso, y el compilador lista lo que quede pendiente.
- Publicas una librería: los archivos
.d.tsdan a sus usuarios autocompletado y comprobaciones. - El framework lo espera. Las aplicaciones de Angular se escriben en TypeScript, Next.js y Astro crean los proyectos nuevos en TypeScript por defecto, y las plantillas de Vite para React, Vue y Svelte tienen cada una una variante en TypeScript.
Elige JavaScript cuando:
- El programa es un script corto, un experimento puntual o un fragmento de código en la consola del navegador.
- Estás aprendiendo a programar por primera vez y quieres menos conceptos a la vez.
- No hay paso de build y no quieres tenerlo. Incluso así,
// @ts-checkcon JSDoc te da algo de comprobación en un archivo.jsnormal.
Migrar un proyecto JavaScript a TypeScript
Una migración no tiene que hacerse de golpe. El compilador acepta JavaScript junto a TypeScript:
{
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
Con allowJs, los archivos .js se compilan y pueden importar desde archivos .ts, y al revés. Después convierte poco a poco:
- Renombra un archivo de
.jsa.tsy corrige los errores que el compilador indique en él. - Empieza por las hojas (módulos de utilidades con pocos imports) y avanza hacia dentro.
- Activa
checkJs, o añade// @ts-checkal principio de archivos.jsconcretos, para comprobar los tipos de los archivos que aún no has renombrado.
En los archivos JavaScript comprobados, los comentarios JSDoc aportan los tipos:
// @ts-check
/**
* @param {number} price
* @param {number} qty
* @returns {number}
*/
function lineTotal(price, qty) {
return price * qty;
}
lineTotal("3", 2);
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Algunos equipos se quedan ahí: archivos JavaScript con tipos en JSDoc, comprobados por tsc, y sin paso de build para el propio código. Otros van hasta el final con .ts. Si activas strict en un proyecto existente, espera muchos errores al principio; la página de strict mode lista qué comprueba cada flag para que puedas activarlos de uno en uno.
Preguntas frecuentes
¿Cuál es la principal diferencia entre TypeScript y JavaScript?
TypeScript añade tipos estáticos a JavaScript. Describes qué es cada valor (name: string, items: Item[]) y el compilador de TypeScript avisa de los errores antes de que el código se ejecute. JavaScript no comprueba nada por adelantado: un tipo equivocado solo aparece cuando se ejecuta esa línea, muchas veces como undefined o un TypeError.
¿Es TypeScript mejor que JavaScript?
Para la mayoría de proyectos que mantiene más de una persona, o que viven más de unas semanas, sí: los tipos detectan categorías enteras de errores, hacen que refactorizar sea seguro y alimentan el autocompletado del editor. Para un script corto, un prototipo rápido o un ejercicio de aprendizaje, JavaScript puro es más rápido de empezar y no necesita configurar un build.
¿Es TypeScript más rápido que JavaScript?
No, y tampoco es más lento. TypeScript se compila a JavaScript y los tipos se borran, así que el código que se ejecuta es el mismo JavaScript que escribirías a mano. El único coste extra es el tiempo de compilación durante el desarrollo.
¿Aprendo primero JavaScript o TypeScript?
Aprende primero lo básico de JavaScript, o a la vez que TypeScript. Todo el comportamiento en tiempo de ejecución (variables, funciones, objetos, arrays, promesas) es JavaScript, y TypeScript solo lo describe. Cuando ya sabes escribir programas pequeños en JavaScript, añadir tipos es un paso corto.
¿Puedo usar TypeScript y JavaScript en el mismo proyecto?
Sí. Pon "allowJs": true en tsconfig.json y el compilador acepta archivos .js junto a los .ts. Añade "checkJs": true (o un comentario // @ts-check en cada archivo) para comprobar también los tipos de los archivos JavaScript, usando los tipos de los comentarios JSDoc. Así se suele migrar un proyecto archivo a archivo.