TS

Configuration

TypeScript · 7 entries

strict Mode

syntax
// tsconfig.json
{ "compilerOptions": { "strict": true } }
example
// strict: true enables ALL of these at once:
// - strictNullChecks: null/undefined not assignable to other types
// - strictFunctionTypes: contravariant function parameter checking
// - strictBindCallApply: type-check bind, call, apply
// - strictPropertyInitialization: class props must be initialized
// - noImplicitAny: error on implicit any
// - noImplicitThis: error on 'this' with implicit any type
// - useUnknownInCatchVariables: catch variable is unknown, not any
// - alwaysStrict: emit "use strict" in every file
output
// strict: true is the recommended baseline for all new projects

Note Always start new projects with strict: true. You can selectively disable individual checks if needed (e.g., "strictPropertyInitialization": false) while keeping the rest. Enabling strict on a large existing JS-to-TS migration can produce thousands of errors — enable checks incrementally in that case.

target & module

syntax
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext"
  }
}
example
// target: which JS version to emit
// "ES5" — maximum compat (IE11), heavy downleveling
// "ES2020" — good baseline for modern browsers
// "ES2022" — class fields, top-level await, cause in Error
// "ESNext" — latest; may change between TS versions

// module: which module system to use
// "commonjs" — Node.js require/exports
// "es2022" — ES modules with top-level await
// "esnext" — latest ES module features
// "node16" / "nodenext" — Node.js ESM with .mjs/.cjs awareness
// "preserve" — keep import/export as written (TS 5.4+)
output
// target controls syntax downleveling; module controls import/export format

Note For bundled apps (Vite, webpack), set target to your browser baseline and module to ESNext — the bundler handles the rest. For Node.js, use module: "node16" or "nodenext" which correctly resolves .mjs/.cjs and package.json "type" fields. The new "preserve" module option (TS 5.4+) emits imports exactly as written.

paths & baseUrl

syntax
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@alias/*": ["src/folder/*"]
    }
  }
}
example
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"],
      "@api/*": ["src/api/*"],
      "@types/*": ["src/types/*"]
    }
  }
}

// In your code:
import { Button } from "@components/Button";
import { formatDate } from "@utils/date";
import type { User } from "@types/user";
output
// Path aliases shorten deep relative imports like ../../../../utils

Note paths only affects TypeScript's type resolution — it does NOT rewrite imports in emitted JS. Your bundler (Vite, webpack) or runtime (ts-node, tsx) needs matching alias config. For Node.js, package.json "imports" with subpath patterns is the modern alternative that works without bundler config.

noEmit & declaration

syntax
{
  "compilerOptions": {
    "noEmit": true,
    "declaration": true
  }
}
example
// noEmit: true — only type-check, don't produce .js files
// Used when a bundler (Vite, esbuild, SWC) handles transpilation
{
  "compilerOptions": {
    "noEmit": true  // tsc is just the type checker
  }
}

// declaration: true — generate .d.ts files alongside .js
// Used for libraries that need to ship type definitions
{
  "compilerOptions": {
    "declaration": true,
    "declarationDir": "./dist/types",
    "emitDeclarationOnly": true  // only .d.ts, no .js
  }
}
output
// noEmit for apps (bundler compiles); declaration for libraries (ship types)

Note Most modern app setups use noEmit: true because tools like Vite, esbuild, and SWC transpile much faster than tsc. Library authors use declaration: true (often with emitDeclarationOnly) to generate .d.ts files while letting another tool handle .js output.

isolatedModules & verbatimModuleSyntax

syntax
{
  "compilerOptions": {
    "isolatedModules": true,
    "verbatimModuleSyntax": true
  }
}
example
// isolatedModules: true
// Ensures each file can be transpiled independently
// Required for: Babel, esbuild, SWC, Vite
// Disallows: const enums across files, namespace merging across files

// verbatimModuleSyntax: true (TS 5.0+, replaces isolatedModules)
// Forces you to use 'import type' for type-only imports

import type { User } from "./models";       // erased at runtime
import { processUser } from "./handlers";   // kept at runtime

// import { User } from "./models";
// Error with verbatimModuleSyntax: 'User' is a type and must use 'import type'
output
// Enforces clean separation of type imports from value imports

Note verbatimModuleSyntax (TS 5.0+) supersedes both isolatedModules and the older importsNotUsedAsValues. It makes the distinction between type and value imports explicit and mandatory. This produces cleaner output and avoids side-effect confusion. Recommended for all new projects.

Project References

syntax
// tsconfig.json
{
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/api" }
  ]
}
example
// Root tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./packages/shared" },
    { "path": "./packages/server" },
    { "path": "./packages/client" }
  ]
}

// packages/server/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "references": [
    { "path": "../shared" }
  ]
}

// Build with: tsc --build
output
// tsc --build only recompiles packages that changed

Note Project references enable incremental builds in monorepos. Each sub-project needs "composite": true. Build with tsc --build (or tsc -b) which understands dependency order. This dramatically speeds up type-checking in large codebases by skipping unchanged packages.

Essential Compiler Options

syntax
// tsconfig.json compilerOptions
example
{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  },
  "include": ["src"]
}
output
// A solid starting tsconfig for a modern bundled web app

Note moduleResolution: "bundler" (TS 5.0+) matches how Vite/webpack/esbuild resolve modules — it supports exports maps, .ts extensions in imports, and does not require file extensions. skipLibCheck: true speeds up compilation by not checking node_modules .d.ts files (only your code is checked).