Menu

tsconfig.json explicado: opções, padrões e exemplos

O tsconfig.json marca uma pasta como projeto TypeScript e define as opções do compilador. As opções que importam (target, module, moduleResolution, strict, rootDir, outDir, include, lib, types, noEmit, skipLibCheck), uma configuração inicial recomendada, extends e o que mudou no TypeScript 7.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

tsconfig.json é o arquivo de configuração de um projeto TypeScript. Quando você roda tsc sem argumentos, o compilador o procura na pasta atual (e depois nas pastas acima), lê as opções em compilerOptions e verifica os arquivos listados em include. Um exemplo pequeno, mas completo:

{
    "compilerOptions": {
        "target": "es2022",
        "module": "nodenext",
        "strict": true,
        "rootDir": "./src",
        "outDir": "./dist"
    },
    "include": ["src"]
}

Isso compila todos os arquivos TypeScript de src para JavaScript em dist, como código ES2022, usando as regras de módulo do Node.js e com todas as verificações strict ligadas. npx tsc --init gera um arquivo inicial mais longo, com um comentário em cada opção.

O arquivo é JSON com comentários: comentários //, comentários /* */ e vírgulas no final são todos aceitos.

Uma configuração inicial recomendada

Para uma aplicação ou script 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"]
}

Ela precisa de npm install --save-dev @types/node para os tipos do Node.js. Com module: "nodenext", o campo "type" do package.json decide se um arquivo .ts é um módulo ES ("type": "module") ou CommonJS ("type": "commonjs", que o npm init -y grava). Use "type": "module" em projetos novos que usam import e export.

Para código que um bundler como Vite, esbuild ou webpack compila, o bundler gera o JavaScript e o tsc só verifica:

{
    "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"]
}

Os starters de frameworks (Vite, Next.js, Angular) geram o próprio tsconfig.json. Parta do deles em vez de substituí-lo.

As opções que importam

OpçãoO que fazPadrão no TypeScript 7
targetVersão de JavaScript da saída; sintaxe mais nova é reescrita para targets mais antigoses2025
libTipos das APIs nativas que o verificador conhece (Array.prototype.at, Map, document)Acompanha o target, mais o DOM
moduleTipo de código de módulo gerado e regras de módulo aplicadasesnext
moduleResolutionComo os caminhos de import são encontrados no disconodenext ou node16 com o module correspondente, senão bundler
strictLiga toda a família de verificações stricttrue
rootDirPasta cuja estrutura é espelhada em outDirA pasta que contém o tsconfig.json
outDirPara onde vão os arquivos .js (e .d.ts)Ao lado de cada arquivo-fonte
include / exclude / filesQuais arquivos fazem parte do projetoTodo arquivo .ts dentro da pasta
typesQuais pacotes @types são carregados sem import[], nenhum
noEmitSó verifica, não grava nadafalse
declarationTambém grava arquivos de declaração de tipos .d.tsfalse
sourceMapGrava arquivos .js.map para depuradoresfalse
esModuleInteropFaz import x from "cjs-package" funcionar com pacotes CommonJStrue (não pode ser desligado)
skipLibCheckPula a verificação de tipos dos arquivos .d.ts, incluindo os de node_modulesfalse

target e lib

target diz em qual versão de JavaScript a saída precisa rodar. Sintaxe mais nova que o target é reescrita: com "target": "es2017", um class field ou um ??= vira código mais antigo. O target mais baixo que o TypeScript 7 aceita é es2015 (es6); o es5 foi removido.

O target não adiciona APIs de runtime que faltam. Descrevê-las é trabalho do lib, e fornecê-las é trabalho de um polyfill. O lib diz ao verificador quais objetos e métodos nativos existem. O padrão dele acompanha o target e também inclui os tipos do DOM do navegador, então document passa na verificação mesmo em um projeto Node.js, a menos que você defina o lib. Usar um método de um padrão mais novo que o seu lib é erro de compilação:

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.

Os exemplos executáveis destas docs usam o lib es2022, então toSorted, Object.groupBy e os novos métodos de Set não estão disponíveis neles.

module e moduleResolution

O module tem três valores sensatos para código novo:

  • nodenext: para código que o Node.js roda. Cada arquivo é ESM ou CommonJS de acordo com a extensão (.mts, .cts) ou o "type" do package.json mais próximo, exatamente como o Node decide. Imports relativos em módulos ES precisam de extensão, escrita como .js mesmo que o fonte seja .ts: import { add } from "./math.js". O moduleResolution acompanha automaticamente.
  • preserve: para código que passa por um bundler. Os imports ficam como foram escritos, e a resolução usa as regras bundler, que permitem imports sem extensão.
  • esnext: saída em módulo ES simples, com resolução bundler. É o padrão quando module não está definido.

Um primeiro erro comum com a configuração do tsc --init vem do npm init -y gravar "type": "commonjs":

src/main.ts(1,10): error TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.

O arquivo usa import, mas o package.json diz que o projeto é CommonJS. Troque o "type" para "module". A página sobre módulos trata de imports e exports em detalhe.

strict e as opções de verificação

"strict": true liga um grupo de verificações de uma vez: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis e useUnknownInCatchVariables. É o padrão no TypeScript 7 e está ligado em todos os exemplos executáveis daqui. Código escrito para o strict mode faz o narrowing antes de usar um valor que pode faltar:

Sem anotação, o tipo de um parâmetro não pode ser inferido, e o noImplicitAny aponta isso:

index.ts(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.

O strict não inclui todas as verificações úteis. Duas que valem a pena adicionar são noUncheckedIndexedAccess (um elemento de array ou uma busca em index signature tem tipo T | undefined) e exactOptionalPropertyTypes (uma propriedade opcional não pode receber undefined explicitamente); o tsc --init liga as duas. Verificações de estilo como noUnusedLocals, noImplicitReturns e noFallthroughCasesInSwitch vêm desligadas por padrão.

Quais arquivos: include, exclude, rootDir, outDir

Sem include ou files, o projeto contém todo arquivo .ts, .tsx e .d.ts da pasta e das subpastas. O node_modules sempre fica de fora. O outDir também fica de fora, mas só enquanto você não define exclude: uma lista exclude própria substitui esse padrão, então inclua a pasta de saída nela. include e exclude aceitam padrões glob:

{
    "include": ["src", "scripts/**/*.ts"],
    "exclude": ["src/**/*.test.ts"]
}

O exclude só filtra o que o include encontrou. Um arquivo importado por outro arquivo incluído continua sendo compilado.

O outDir é para onde vai a saída, e o rootDir é a parte da árvore de fontes espelhada nela: com "rootDir": "./src", src/api/users.ts vira dist/api/users.js. Defina os dois. O rootDir tem como padrão a pasta que contém o tsconfig.json, então, se você definir só o outDir com os fontes em src, o TypeScript 7 para com:

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.

Opções de saída: noEmit, declaration, sourceMap

  • "noEmit": true transforma o tsc em um verificador de tipos puro. Use quando outra ferramenta (um bundler, o tsx, o type stripping do Node.js) gera o JavaScript.
  • "declaration": true grava um arquivo .d.ts por módulo, os tipos sem o código. Bibliotecas precisam disso para que os usuários recebam os tipos. O declarationMap adiciona mapas para o "ir para a definição" levar ao fonte .ts.
  • "sourceMap": true grava arquivos .js.map para que depuradores e stack traces apontem para as linhas do .ts.
  • "noEmitOnError": true não grava nada enquanto houver erros de tipo. Sem ele, o tsc reporta os erros e grava o JavaScript mesmo assim.

types, esModuleInterop e skipLibCheck

types lista os pacotes @types carregados globalmente, sem import. O padrão do TypeScript 7 é uma lista vazia, então depois de npm install --save-dev @types/node você também adiciona "types": ["node"]; senão process e require continuam desconhecidos (error TS2591: Cannot find name 'process'). Test runners com funções globais, como o describe do Jest, entram na mesma lista.

O esModuleInterop faz imports default de pacotes CommonJS funcionarem (import express from "express"). Ele está sempre ligado no TypeScript 7, e definir false é um erro.

O skipLibCheck pula a verificação de tipos dos arquivos de declaração. Ele acelera os builds e evita erros dentro de node_modules que você não consegue corrigir, com o custo de não notar conflitos entre os tipos de duas bibliotecas. A maioria dos projetos o liga.

Compartilhando configurações com extends

O extends carrega outra configuração e deixa este arquivo sobrescrever partes dela:

{
    "extends": "./tsconfig.base.json",
    "compilerOptions": {
        "rootDir": "./src",
        "outDir": "./dist"
    },
    "include": ["src"]
}

As compilerOptions são mescladas opção por opção, enquanto include, exclude e files da base são substituídos, não mesclados, se este arquivo os definir. Caminhos no arquivo base são resolvidos em relação ao próprio arquivo base. O extends também aceita um pacote: o projeto @tsconfig/bases publica um por ambiente, por exemplo npm install --save-dev @tsconfig/node24 e depois "extends": "@tsconfig/node24/tsconfig.json".

Para ver as configurações finais depois de aplicar todos os extends e padrões, rode:

npx tsc --showConfig

Opções removidas no TypeScript 7

O TypeScript 6 marcou estas configurações como obsoletas e o TypeScript 7 as removeu. Uma configuração que ainda usa alguma falha com error TS5108 ou TS5102, por exemplo Option 'baseUrl' has been removed. Please remove it from your configuration.

Configuração removidaUse no lugar
"target": "es5"es2015 ou posterior
"moduleResolution": "node" (node10) ou "classic"nodenext ou bundler
"module": "amd", "umd", "system", "none"nodenext, esnext ou preserve, e um bundler para outros formatos
baseUrlEntradas de paths relativas ao arquivo tsconfig
outFileUm bundler
downlevelIterationNada: targets a partir de es2015 suportam iteração nativamente
"esModuleInterop": false, "allowSyntheticDefaultImports": false, "alwaysStrict": falseRemova a linha; essas opções estão sempre ligadas

A página do TypeScript 7 lista as outras mudanças dessa versão, incluindo os novos padrões que esta tabela não cobre.

Perguntas frequentes

O que é o tsconfig.json?

É o arquivo de configuração de um projeto TypeScript. A presença dele marca a pasta como raiz do projeto, compilerOptions define como o compilador verifica e gera o código, e include, exclude ou files dizem quais arquivos fazem parte do projeto. Rodar tsc sem argumentos lê esse arquivo.

Como criar um arquivo tsconfig.json?

Rode npx tsc --init na pasta do projeto (com o TypeScript instalado). Ele grava um tsconfig.json com configurações recomendadas e um comentário em cada opção. Você também pode escrever o arquivo à mão; {} é um tsconfig válido que usa todos os padrões.

Qual valor usar em target no tsconfig?

A versão mais antiga de JavaScript em que o seu código precisa rodar. Para o Node.js atual, es2022 ou posterior é seguro; o padrão do TypeScript 7 é es2025. O target controla qual sintaxe nova é reescrita para engines antigas e também escolhe o lib padrão, o conjunto de APIs nativas que o verificador conhece.

Qual é a diferença entre module e moduleResolution?

module decide o tipo de código de módulo que o compilador gera (ES import/export ou CommonJS require) e quais regras de módulo valem. moduleResolution decide como um caminho de import como "./utils.js" ou "lodash" é encontrado no disco. Use nodenext para código que o Node.js roda e module: "preserve" (que implica resolução bundler) para código que passa por um bundler.

O tsconfig.json pode ter comentários?

Sim. O compilador o lê como JSON com comentários: comentários // e /* */ e vírgulas no final são permitidos, e é por isso que o tsc --init gera um arquivo cheio de opções comentadas. Outras ferramentas que o leem como JSON estrito podem falhar com eles.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR