tsconfig.json es el archivo de configuración de un proyecto TypeScript. Cuando ejecutas tsc sin argumentos, el compilador lo busca en la carpeta actual (y luego en las carpetas padre), lee las opciones de compilerOptions y comprueba los archivos que indica include. Uno pequeño pero completo:
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"strict": true,
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
Esto compila todos los archivos TypeScript de src a JavaScript en dist, como código ES2022, con las reglas de módulos de Node.js y todas las comprobaciones estrictas activadas. npx tsc --init genera un archivo inicial más largo con un comentario en cada opción.
El archivo es JSON con comentarios: se aceptan los comentarios //, los comentarios /* */ y las comas finales.
Una configuración inicial recomendada
Para una aplicación o un script de Node.js:
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"target": "es2024",
"lib": ["es2024"],
"module": "nodenext",
"types": ["node"],
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"sourceMap": true
},
"include": ["src"]
}
Necesita npm install --save-dev @types/node para los tipos de Node.js. Con module: "nodenext", el campo "type" de package.json decide si un archivo .ts es un módulo ES ("type": "module") o CommonJS ("type": "commonjs", que es lo que escribe npm init -y). Usa "type": "module" en proyectos nuevos que usen import y export.
Para código que construye un bundler como Vite, esbuild o webpack, el bundler escribe el JavaScript y tsc solo comprueba:
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "dom"],
"module": "preserve",
"noEmit": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
Las plantillas de los frameworks (Vite, Next.js, Angular) generan su propio tsconfig.json. Parte del suyo en lugar de sustituirlo.
Las opciones que importan
| Opción | Qué hace | Valor por defecto en TypeScript 7 |
|---|---|---|
target | Versión de JavaScript de la salida; la sintaxis nueva se reescribe para targets antiguos | es2025 |
lib | Tipos de las APIs integradas que conoce el comprobador (Array.prototype.at, Map, document) | Coincide con target, más el DOM |
module | Tipo de código de módulos que se genera y reglas de módulos que se aplican | esnext |
moduleResolution | Cómo se encuentran en disco las rutas de import | nodenext o node16 con el module correspondiente, si no bundler |
strict | Activa toda la familia de comprobaciones estrictas | true |
rootDir | Carpeta cuya estructura se replica en outDir | La carpeta que contiene tsconfig.json |
outDir | Dónde van los archivos .js (y .d.ts) | Junto a cada archivo fuente |
include / exclude / files | Qué archivos forman parte del proyecto | Todos los archivos .ts bajo la carpeta |
types | Qué paquetes @types se cargan sin un import | [], ninguno |
noEmit | Solo comprobar, no escribir nada | false |
declaration | Escribir también archivos de declaración de tipos .d.ts | false |
sourceMap | Escribir archivos .js.map para los depuradores | false |
esModuleInterop | Permite que import x from "cjs-package" funcione con paquetes CommonJS | true (no se puede desactivar) |
skipLibCheck | Omite la comprobación de tipos de los archivos .d.ts, incluidos los de node_modules | false |
target y lib
target indica en qué versión de JavaScript debe ejecutarse la salida. La sintaxis más nueva que el target se reescribe: con "target": "es2017", un campo de clase o ??= se convierte en código más antiguo. El target más bajo que acepta TypeScript 7 es es2015 (es6); es5 se eliminó.
target no añade las APIs de ejecución que falten. Describirlas es trabajo de lib, y aportarlas es trabajo de un polyfill. lib le dice al comprobador qué objetos y métodos integrados existen. Su valor por defecto sigue a target e incluye también los tipos del DOM del navegador, así que document pasa la comprobación incluso en un proyecto de Node.js salvo que fijes lib tú mismo. Usar un método de un estándar más nuevo que tu lib es un error de compilación:
src/b.ts(1,24): error TS2550: Property 'toSorted' does not exist on type 'number[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2023' or later.
Los ejemplos ejecutables de esta documentación usan el lib es2022, así que toSorted, Object.groupBy y los nuevos métodos de Set no están disponibles en ellos.
module y moduleResolution
module tiene tres valores razonables para código nuevo:
nodenext: para código que ejecuta Node.js. Cada archivo es ESM o CommonJS según su extensión (.mts,.cts) o el"type"delpackage.jsonmás cercano, exactamente como decide Node. Los imports relativos en los módulos ES necesitan extensión de archivo, escrita como.jsaunque el código fuente sea.ts:import { add } from "./math.js".moduleResolutionse ajusta automáticamente.preserve: para código que procesa un bundler. Los imports se dejan tal como se escribieron, y la resolución usa las reglas debundler, que permiten imports sin extensión.esnext: salida de módulos ES sin más, con resoluciónbundler. Es el valor por defecto cuando no se fijamodule.
Un primer error habitual con la configuración de tsc --init viene de que npm init -y escribe "type": "commonjs":
src/main.ts(1,10): error TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.
El archivo usa import, pero package.json dice que el proyecto es CommonJS. Cambia "type" a "module". La página de módulos explica en detalle los imports y los exports.
strict y las opciones de comprobación
"strict": true activa de golpe un grupo de comprobaciones: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis y useUnknownInCatchVariables. Es el valor por defecto en TypeScript 7 y está activado en todos los ejemplos ejecutables de aquí. El código escrito para el modo estricto estrecha el tipo antes de usar un valor que puede faltar:
Sin anotación, el tipo de un parámetro no se puede inferir, y noImplicitAny lo señala:
index.ts(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.
strict no incluye todas las comprobaciones útiles. Dos que vale la pena añadir son noUncheckedIndexedAccess (un elemento de un array o una búsqueda en una firma de índice tiene el tipo T | undefined) y exactOptionalPropertyTypes (una propiedad opcional no se puede fijar explícitamente a undefined); tsc --init activa las dos. Las comprobaciones de estilo como noUnusedLocals, noImplicitReturns y noFallthroughCasesInSwitch están desactivadas por defecto.
Qué archivos: include, exclude, rootDir, outDir
Sin include ni files, el proyecto contiene todos los archivos .ts, .tsx y .d.ts de la carpeta y sus subcarpetas. node_modules siempre queda fuera. El outDir también, pero solo mientras no hayas fijado exclude: una lista exclude propia sustituye ese valor por defecto, así que añade a ella la carpeta de salida. include y exclude aceptan patrones glob:
{
"include": ["src", "scripts/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}
exclude solo filtra lo que encontró include. Un archivo que importa otro archivo incluido se sigue compilando.
outDir es donde va la salida, y rootDir es la parte del árbol de código fuente que se replica en ella: con "rootDir": "./src", src/api/users.ts se convierte en dist/api/users.js. Fija los dos. rootDir vale por defecto la carpeta que contiene tsconfig.json, así que si solo fijas outDir mientras el código está en src, TypeScript 7 se detiene con:
error TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
Opciones de salida: noEmit, declaration, sourceMap
"noEmit": trueconviertetscen un comprobador de tipos puro. Úsalo cuando otra herramienta (un bundler,tsx, el type stripping de Node.js) produce el JavaScript."declaration": trueescribe un archivo.d.tspor módulo, con los tipos y sin el código. Las librerías lo necesitan para que sus usuarios tengan tipos.declarationMapañade mapas para que "ir a la definición" lleve al código.ts."sourceMap": trueescribe archivos.js.mappara que los depuradores y las trazas de error apunten a las líneas del.ts."noEmitOnError": trueno escribe nada mientras haya errores de tipo. Sin esta opción,tscinforma de los errores y aun así escribe el JavaScript.
types, esModuleInterop y skipLibCheck
types lista los paquetes @types que se cargan de forma global, sin un import. El valor por defecto de TypeScript 7 es una lista vacía, así que después de npm install --save-dev @types/node también añades "types": ["node"]; si no, process y require siguen siendo desconocidos (error TS2591: Cannot find name 'process'). Los test runners con funciones globales, como el describe de Jest, van en la misma lista.
esModuleInterop hace que funcionen los imports por defecto de paquetes CommonJS (import express from "express"). Siempre está activado en TypeScript 7, y ponerlo a false es un error.
skipLibCheck omite la comprobación de tipos de los archivos de declaración. Acelera los builds y evita errores dentro de node_modules que no puedes corregir, a cambio de no notar los conflictos entre los tipos de dos librerías. La mayoría de proyectos lo activa.
Compartir configuración con extends
extends carga otra configuración y deja que este archivo sobrescriba partes de ella:
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
Las compilerOptions se combinan opción por opción, mientras que include, exclude y files de la base se sustituyen, no se combinan, si este archivo los fija. Las rutas del archivo base se resuelven respecto al archivo base. extends también acepta un paquete: el proyecto @tsconfig/bases publica uno por entorno, por ejemplo npm install --save-dev @tsconfig/node24 y luego "extends": "@tsconfig/node24/tsconfig.json".
Para ver la configuración final después de aplicar todos los extends y los valores por defecto, ejecuta:
npx tsc --showConfig
Opciones eliminadas en TypeScript 7
TypeScript 6 marcó estas opciones como obsoletas y TypeScript 7 las eliminó. Una configuración que aún use alguna falla con error TS5108 o TS5102, por ejemplo Option 'baseUrl' has been removed. Please remove it from your configuration.
| Opción eliminada | Qué usar en su lugar |
|---|---|
"target": "es5" | es2015 o posterior |
"moduleResolution": "node" (node10) o "classic" | nodenext o bundler |
"module": "amd", "umd", "system", "none" | nodenext, esnext o preserve, y un bundler para otros formatos |
baseUrl | Entradas de paths relativas al archivo tsconfig |
outFile | Un bundler |
downlevelIteration | Nada: los targets desde es2015 admiten la iteración de forma nativa |
"esModuleInterop": false, "allowSyntheticDefaultImports": false, "alwaysStrict": false | Quita la línea; estas opciones siempre están activadas |
La página de TypeScript 7 lista los demás cambios de esa versión, incluidos los nuevos valores por defecto que no cubre esta tabla.
Preguntas frecuentes
¿Qué es tsconfig.json?
Es el archivo de configuración de un proyecto TypeScript. Su presencia marca la carpeta como raíz del proyecto, compilerOptions fija cómo comprueba y genera código el compilador, e include, exclude o files indican qué archivos pertenecen al proyecto. Ejecutar tsc sin argumentos lo lee.
¿Cómo creo un archivo tsconfig.json?
Ejecuta npx tsc --init en la carpeta del proyecto (con TypeScript instalado). Escribe un tsconfig.json con la configuración recomendada y un comentario en cada opción. También puedes escribir el archivo a mano; {} es un tsconfig válido que usa todos los valores por defecto.
¿Qué valor debe tener target en tsconfig?
La versión de JavaScript más antigua en la que tiene que ejecutarse tu código. Para un Node.js actual, es2022 o posterior es seguro; el valor por defecto de TypeScript 7 es es2025. target controla qué sintaxis nueva se reescribe para motores antiguos y también elige el lib por defecto, el conjunto de APIs integradas que conoce el comprobador.
¿Qué diferencia hay entre module y moduleResolution?
module decide qué tipo de código de módulos escribe el compilador (import/export de ES o require de CommonJS) y qué reglas de módulos se aplican. moduleResolution decide cómo se encuentra en disco una ruta de import como "./utils.js" o "lodash". Usa nodenext para código que ejecuta Node.js, y module: "preserve" (que implica la resolución bundler) para código que procesa un bundler.
¿Puede tsconfig.json tener comentarios?
Sí. El compilador lo lee como JSON con comentarios: se admiten los comentarios // y /* */ y las comas finales, y por eso tsc --init escribe un archivo lleno de opciones comentadas. Otras herramientas que lo lean como JSON estricto pueden fallar con ellos.