El archivo tsconfig.json le dice a TypeScript qué revisar, con qué rigor y qué JavaScript generar. Vemos qué crea tsc --init, armamos uno para un proyecto de Node 24 que se puede ejecutar sin compilar y comprobamos lo que cambian las opciones más importantes.
También te puede interesar
Lo que crea tsc –init
En una carpeta vacía, npx tsc --init genera este archivo con TypeScript 7.0.2. Lo copiamos tal cual:
npx tsc --init
{
// Visit https://aka.ms/tsconfig to read more about this file
"compilerOptions": {
// File Layout
// "rootDir": "./src",
// "outDir": "./dist",
// Environment Settings
// See also https://aka.ms/tsconfig/module
"module": "nodenext",
"target": "esnext",
"types": [],
// For nodejs:
// "lib": ["esnext"],
// "types": ["node"],
// and npm install -D @types/node
// Other Outputs
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// Stricter Typechecking Options
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// Style Options
// "noImplicitReturns": true,
// "noImplicitOverride": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noFallthroughCasesInSwitch": true,
// "noPropertyAccessFromIndexSignature": true,
// Recommended Options
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
}
}Es un buen punto de partida, pero piensa en una biblioteca para el navegador: genera declaraciones (declaration), mapas de código y la opción de JSX para React, y deja "types": [], sin los tipos de Node. Para un programa de Node conviene ajustarlo. Los comentarios con // están permitidos en este archivo, aunque no sean JSON estricto.
Un tsconfig.json para Node 24
El proyecto de ejemplo calcula el total de un carrito. Tiene esta estructura:
precios/
package.json
tsconfig.json
src/
index.ts
precio.ts{
"compilerOptions": {
// Qué JavaScript se genera y qué módulos se usan
"target": "es2024",
"module": "nodenext",
// Dónde está el código y adónde va lo compilado
"rootDir": "src",
"outDir": "dist",
// La revisión: estricta, y un poco más
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Para que Node 24 pueda ejecutar los .ts directamente
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"rewriteRelativeImportExtensions": true,
// Los tipos de Node y nada más
"types": ["node"],
"skipLibCheck": true
}
}| Opción | Qué hace |
|---|---|
target | Qué versión de JavaScript genera. Node 24 entiende es2024 completo, así que tsc no tiene que traducir nada moderno. |
module: "nodenext" | Sigue las reglas de módulos de Node: con "type": "module" en package.json, los archivos son módulos ES. |
rootDir, outDir | De dónde lee el código y dónde deja el JavaScript al compilar. |
strict | Activa a la vez las comprobaciones serias: null no cabe en cualquier tipo, nada de any implícito, y varias más. Siempre encendido. |
noUncheckedIndexedAccess | Leer lista[i] o objeto[clave] da T | undefined, porque ese elemento puede no existir. |
noImplicitOverride | Obliga a escribir override al redefinir un método de la clase madre. |
erasableSyntaxOnly | Prohíbe lo que no se puede «borrar» sin más, como enum: Node 24 ejecuta los .ts quitando los tipos y no sabe traducir eso. |
verbatimModuleSyntax | Exige import type para lo que solo es un tipo, para que quede claro qué import desaparece al ejecutar. |
rewriteRelativeImportExtensions | Permite escribir import … from "./precio.ts" y, al compilar, lo cambia a ./precio.js. |
types: ["node"] | Carga los tipos de Node (paquete @types/node) y ninguno más. |
skipLibCheck | No revisa los .d.ts de los paquetes: acelera y evita errores ajenos. |
Y el código:
export interface Articulo {
nombre: string;
precio: number;
}
export function total(articulos: Articulo[], iva = 0.16): number {
const subtotal = articulos.reduce((s, a) => s + a.precio, 0);
return Math.round(subtotal * (1 + iva) * 100) / 100;
}import { total, type Articulo } from "./precio.ts";
const carrito: Articulo[] = [
{ nombre: "Audífonos", precio: 1299.99 },
{ nombre: "Cable HDMI", precio: 189 },
];
const formato = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
console.log("Total con IVA:", formato.format(total(carrito)));
console.log("Primer artículo:", carrito[0]?.nombre);Revisar, ejecutar y compilar
Con el tsconfig.json en la carpeta, tsc sin argumentos lo lee. --noEmit revisa los tipos sin generar nada; si no hay errores, no dice nada:
npx tsc --noEmit
tsc(sin errores)
Node 24 ejecuta el .ts directamente, quitando los tipos. Ojo: así no se revisan, por eso tsc --noEmit va antes:
node src/index.ts
salidaTotal con IVA: $1,727.23 Primer artículo: Audífonos
Para distribuir JavaScript, tsc sin --noEmit compila a dist/. El import a ./precio.ts se ha reescrito a ./precio.js, y los tipos han desaparecido:
npx tsc ls dist
salidaindex.js precio.js
import { total } from "./precio.js";
const carrito = [
{ nombre: "Audífonos", precio: 1299.99 },
{ nombre: "Cable HDMI", precio: 189 },
];
const formato = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
console.log("Total con IVA:", formato.format(total(carrito)));
console.log("Primer artículo:", carrito[0]?.nombre);En package.json, los scripts dejan las tres órdenes a mano:
{
"name": "precios",
"private": true,
"type": "module",
"scripts": {
"inicio": "node src/index.ts",
"revisar": "tsc --noEmit",
"compilar": "tsc"
}
}Lo que cambian tres opciones
strict. Sin él, un parámetro sin tipo es any y nadie se queja. Con él:
function doble(x) {
return x * 2;
}
console.log(doble("tres"));npx tsc --noEmit --strict false --locale es implicito.ts
tsc(sin errores)
npx tsc --noEmit --strict --locale es implicito.ts
tscimplicito.ts(1,16): error TS7006: El parámetro 'x' tiene un tipo 'any' implícitamente.
noUncheckedIndexedAccess. Leer una clave que no existe da undefined. Sin la opción, TypeScript lo deja pasar y el programa falla al ejecutar:
const precios: Record<string, number> = { webcam: 899, bocina: 649.5 };
const p = precios["teclado"];
console.log(p.toFixed(2));npx tsc --noEmit --strict --locale es indice.ts
tsc(sin errores)
node indice.ts
salidafile:///w/tsconfig/demos/indice.ts:3
console.log(p.toFixed(2));
^
TypeError: Cannot read properties of undefined (reading 'toFixed')
Node.js v24.22.0npx tsc --noEmit --strict --noUncheckedIndexedAccess --locale es indice.ts
tscindice.ts(3,13): error TS18048: "p" es posiblemente "undefined".
verbatimModuleSyntax. Importar una interfaz como si fuera un valor es un error, porque al ejecutar esa interfaz no existe:
import { Articulo } from "./tipos.ts";
const a: Articulo = { nombre: "Webcam", precio: 899 };
console.log(a);npx tsc --noEmit --strict --module nodenext --verbatimModuleSyntax --allowImportingTsExtensions --locale es importar.ts
tscimportar.ts(1,10): error TS1484: “Articulo” es un tipo y debe importarse mediante una importación de solo tipo cuando “verbatimModuleSyntax” está habilitado.
La solución es import type { Articulo }, o import { total, type Articulo } si en la misma línea hay valores y tipos, como en index.ts.
npx tsc --noEmit src/index.ts en una carpeta que tiene tsconfig.json, TypeScript 7 no lo usa y te avisa con un error: error TS5112: tsconfig.json está presente, pero no se cargará si se especifican archivos en la línea de comandos. Use '--ignoreConfig' para omitir este error. Para revisar el proyecto, npx tsc --noEmit sin nombres de archivo.Todo el código de esta página se comprobó con TypeScript 7.0.2 en modo estricto (--strict --locale es) y se ejecutó con Node.js 24.22 en un contenedor limpio antes de publicarla; los mensajes de error y las salidas están copiados de esa ejecución. Documentación oficial: TSConfig Reference.