Como Configurar tsconfig no TypeScript
tsconfig essencial: strict, moduleResolution e paths sem atirar no escuro.
Por que isso é importante
Configurar tsconfig no TypeScript começa por strict e moduleResolution alinhados ao bundler. Path aliases sem baseUrl certo só geram import quebrado.
O Que É o tsconfig.json
O tsconfig.json é um arquivo JSON na raiz do seu projeto que diz pro compilador TypeScript como se comportar. Sem ele, o compilador usa configurações padrão que podem não servir pro seu caso. Com ele, você controla tudo: pra qual versão de JavaScript compilar, quais arquivos incluir, quão rigorosa deve ser a checagem de tipos.
Quando você roda tsc (o compilador TypeScript), ele procura um tsconfig.json no diretório atual e sobe até a raiz do disco. Se não achar, compila com defaults. Em projetos profissionais, o tsconfig é um dos primeiros arquivos que você cria.
O arquivo tem três seções principais: compilerOptions (como compilar), include (quais arquivos compilar) e exclude (quais ignorar). A maior parte do trabalho fica no compilerOptions, que tem mais de 100 opções. Mas calma: na prática, você usa umas 15 a 20.
Passo a Passo: Configurando do Zero
Vamos montar um tsconfig.json partindo do zero. Cada passo adiciona uma camada de configuração.
compilerOptions: As Opções que Importam
Vamos ver cada grupo de opções com exemplos. Não precisa decorar tudo: entenda o conceito e copie a configuração que serve pro seu projeto.
Target e Module: Saída do Compilador
{
"compilerOptions": {
// Pra qual versão de JS compilar
"target": "ES2022",
// Sistema de módulos
"module": "NodeNext",
// Como resolver imports de módulos
"moduleResolution": "NodeNext",
// Pasta de saída dos arquivos compilados
"outDir": "./dist",
// Pasta raiz dos fontes
"rootDir": "./src",
// APIs disponíveis (DOM, ES2020, etc.)
"lib": ["ES2022"]
}
}
// Target comuns:
// "ES2015" - suporte amplo (async/await nativo não incluso)
// "ES2017" - async/await nativo
// "ES2020" - optional chaining, nullish coalescing
// "ES2022" - top-level await, at(), cause em Error
// "ESNext" - sempre a versão mais recente
Strict: Segurança Máxima
{
"compilerOptions": {
// Liga tudo de uma vez (recomendado)
"strict": true,
// O que strict ativa internamente:
// "strictNullChecks": true - null/undefined explícitos
// "noImplicitAny": true - proíbe any implícito
// "strictFunctionTypes": true - checagem estrita de funções
// "strictBindCallApply": true - bind/call/apply tipados
// "noImplicitThis": true - this precisa ter tipo
// "alwaysStrict": true - "use strict" em todo arquivo
// "strictPropertyInitialization": true - props de classe iniciadas
// Extras que valem ativar junto:
"noUncheckedIndexedAccess": true, // array[i] pode ser undefined
"noImplicitReturns": true, // todas as branches retornam
"noFallthroughCasesInSwitch": true // switch sem break é erro
}
}
Paths: Aliases de Import
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
// Alias simples pra src/
"@/*": ["src/*"],
// Aliases específicos por módulo
"@/utils/*": ["src/utils/*"],
"@/components/*": ["src/components/*"],
"@/types/*": ["src/types/*"],
"@/services/*": ["src/services/*"]
}
}
}
// Antes (sem paths):
import { formatDate } from "../../../utils/date";
import { Button } from "../../components/ui/Button";
// Depois (com paths):
import { formatDate } from "@/utils/date";
import { Button } from "@/components/ui/Button";
// ATENÇÃO: paths só funciona no TypeScript.
// Se usar Node.js puro, configure também tsconfig-paths.
// Se usar bundler (Webpack, Vite), configure o alias lá também.
esModuleInterop e Resolução de Módulos
{
"compilerOptions": {
// Importar módulos CommonJS como default import
"esModuleInterop": true,
// Checagem consistente de casing em imports
"forceConsistentCasingInFileNames": true,
// Permitir import de JSON
"resolveJsonModule": true,
// Isolar cada arquivo como módulo
"isolatedModules": true,
// Não emitir JS (quando outro tool compila, ex: Babel, SWC)
"noEmit": true,
// Gerar source maps pra debug
"sourceMap": true,
// Gerar arquivos .d.ts de declaração
"declaration": true
}
}
// Com esModuleInterop:
import express from "express"; // funciona
import * as express from "express"; // também funciona
// Sem esModuleInterop:
import express from "express"; // ERRO
import * as express from "express"; // única opção
Include, Exclude e Extends
{
// Herdar configuração base
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
// Quais arquivos/pastas compilar
"include": [
"src/**/*.ts",
"src/**/*.tsx"
],
// Quais arquivos/pastas ignorar
"exclude": [
"node_modules",
"dist",
"coverage",
"**/*.test.ts",
"**/*.spec.ts"
]
}
// Presets populares pra extends:
// @tsconfig/node20 - Node.js 20
// @tsconfig/node18 - Node.js 18
// @tsconfig/recommended - base recomendada
// @tsconfig/strictest - mais rigoroso possível
// Instalar:
// npm install --save-dev @tsconfig/node20
Configurações Prontas por Tipo de Projeto
Em vez de montar do zero toda vez, aqui vão configs prontas pra cada cenário. Copie, cole e ajuste conforme seu projeto.
tsconfig para API Node.js
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"declaration": true,
"sourceMap": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
tsconfig para React (Next.js / Vite)
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"skipLibCheck": true,
"allowJs": true,
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules"]
}
Perceba que no projeto React com bundler, o noEmit é true porque quem compila o código é o Webpack, Vite ou SWC. O TypeScript só checa tipos. No Node.js, o TypeScript compila pra JavaScript, então outDir e declaration fazem sentido.
Erros Comuns na Configuração do tsconfig
Armadilhas que pegam em todo projeto
Não ativar strict: configuração padrão sem strict deixa passar null, any implícito e vários bugs silenciosos. Sempre ative strict. Resolva os erros que aparecem em vez de desligar a proteção.
Confundir module com moduleResolution: module define o formato de saída (CommonJS, ESNext). moduleResolution define como o TypeScript encontra arquivos importados (node, bundler, NodeNext). Os dois precisam combinar.
Paths sem baseUrl: paths aliases não funcionam sem baseUrl definido. Sempre coloque "baseUrl": "." junto com paths. E lembre: o bundler ou runtime também precisa saber dos aliases.
Include muito amplo: incluir "**/*.ts" pega scripts de build, testes e tudo mais. Seja específico: "src/**/*.ts". Use exclude pra remover o que não deve ser compilado.
Copiar tsconfig sem entender: cada projeto tem necessidades diferentes. Um tsconfig de projeto React não serve pra API Node.js. Entenda cada opção antes de copiar.
Checklist de Configuração do tsconfig
Configure TypeScript com Confiança
O tsconfig.json é a base de todo projeto TypeScript profissional. No CrazyStack, cada projeto começa com uma configuração sólida: strict mode, paths aliases, presets otimizados. Você constrói um SaaS completo com Node.js e React, aprendendo não só a configurar mas a entender cada decisão por trás do setup.
Se você quer parar de copiar configurações e começar a entender o que cada opção faz, esse é o caminho.