Skip to main content

tsconfig.json

The tsconfig.json file controls how TypeScript compiles your code. Most projects inherit from a base config and only override what they need.

tsconfig.json
{
"compilerOptions": {
/* Language */
"target": "ES2022", // JS version to compile to
"lib": ["ES2022"], // type definitions to include
"module": "NodeNext", // module system (ESM for modern Node)
"moduleResolution": "NodeNext",

/* Output */
"outDir": "./dist", // compiled output directory
"rootDir": "./src", // source files directory
"declaration": true, // generate .d.ts files
"declarationMap": true, // source maps for .d.ts
"sourceMap": true, // source maps for debugging

/* Strictness — turn ALL of these on */
"strict": true, // enables all strict checks below
"noUncheckedIndexedAccess": true, // arr[0] is T | undefined
"noImplicitOverride": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,

/* Module resolution */
"esModuleInterop": true,
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,

/* Paths (optional — for cleaner imports) */
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"], // include DOM types
"module": "ESNext",
"moduleResolution": "Bundler", // Vite handles resolution

"jsx": "react-jsx", // React 17+ JSX transform
"jsxImportSource": "react",

"strict": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,

"esModuleInterop": true,
"resolveJsonModule": true,
"isolatedModules": true, // required for Vite
"skipLibCheck": true, // skip .d.ts file checks (faster)

"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true, // Next.js handles compilation
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve", // Next.js transforms JSX
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

Key Options Explained

OptionWhat It Does
strict: trueEnables strictNullChecks, noImplicitAny, and 6 other checks
strictNullChecksnull and undefined are distinct types (prevents most null errors)
noImplicitAnyForbids implicit any — forces you to annotate
noUncheckedIndexedAccessarr[0] returns T | undefined — safer array access
targetWhat JS version to emit
moduleWhat module syntax to emit
skipLibCheckSkips type-checking of .d.ts files — speeds up builds
Always enable strict: true

It enables multiple checks that prevent the most common TypeScript bugs. Never turn it off.

Path Aliases

Configure @/ to point to src/ for cleaner imports:

// Without path alias
import { formatDate } from '../../../utils/format';

// With @/* alias
import { formatDate } from '@/utils/format';

Vite also needs the alias configured:

vite.config.ts
import { defineConfig } from 'vite'
import path from 'path'

export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})