TypeScript: A Detailed Explanation of TypeScript's…

Last updated: 2026-08-26

tsconfig.json is the configuration hub for TypeScript projects—it tells the compiler how to compile the code, check types, and output results. Understanding these configuration options is essential for ensuring your TypeScript project runs smoothly.

1. tsconfig.json Basics

(1) Create a configuration file

BASH
# Automatically Generate Default Configuration
tsc --init

# Generate a detailed configuration with comments
tsc --init --typescript

(2) Basic Structure

JSON
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

(3) Top-level fields

Field Description
compilerOptions Compiler Options
include Included files (glob mode)
exclude Excluded files
files List of explicitly specified files
references Project References (monorepo)
extends Inherit from another configuration file


2. Core Compilation Options

(1) target—compilation target

Specify the version of the compiled JavaScript:

JSON
{
  "compilerOptions": {
    "target": "ES2020"
  }
}
Value Description Recommended Scenarios
"ES5" Compatible with older browsers Supports IE11
"ES2018" Modern browsers General Web projects
"ES2020" Latest Stable Features Recommended
"ESNext" Latest Proposal Features Cutting-Edge Projects
💡 Tip: The target option only affects syntax transformation (e.g., arrow functions → regular functions); it does not affect type checking. Type checking is controlled by the lib option.

(2) module—Module System

JSON
{
  "compilerOptions": {
    "module": "ESNext"
  }
}
Value Description Recommended Scenarios
"CommonJS" Node.js Default Node Project
"ESNext" / "ES2015" ES Modules Browser/Deno/Vite
"UMD" General-Purpose Modules Library Releases
"System" SystemJS Legacy Module Loader

(3) moduleResolution—Module Resolution Strategy

JSON
{
  "compilerOptions": {
    "moduleResolution": "node"
  }
}
Value Description
"node" Node.js style (recommended)
"classic" Old TS Style (Not Recommended)
"bundler" Vite/esbuild and Other Build Tools (TS 5.0+)

(4) lib—Type Library

Specify the available built-in type declarations:

JSON
{
  "compilerOptions": {
    "lib": ["ES2020", "DOM", "DOM.Iterable"]
  }
}
Value Type provided
"ES2020" Promise, Array.flat, BigInt, etc.
"DOM" document, window, HTMLElement, etc.
"DOM.Iterable" NodeList 's for...of
"ES2020.String" ES2020 Methods for Strings
"ES2020.Promise" Promise.allSettled, etc.
💡 Tip: The target automatically includes the corresponding lib. If you explicitly specify a lib, it will no longer be automatically included—you’ll need to manually list all required libraries. Web projects typically require ["ES2020", "DOM"].

(5) outDir and rootDir

JSON
{
  "compilerOptions": {
    "outDir": "./dist",      // Compilation Output Directory
    "rootDir": "./src",      // Source Code Root Directory(Preserve the directory structure)
    "declaration": true,     // Generate .d.ts Statement
    "sourceMap": true        // Generate .js.map Source Code Mapping
  }
}


3. Strict Mode Option

(1) Strict mode fully enabled

JSON
{
  "compilerOptions": {
    "strict": true
  }
}

strict: true is equivalent to enabling all of the following options at the same time:

Option Description
strictNullChecks null/undefined cannot be assigned to other types
strictFunctionTypes Inverse Check of Function Parameters
strictBindCallApply Strict checking of bind/call/apply
strictPropertyInitialization Class properties must be initialized
noImplicitAny Implicit any prohibited
noImplicitThis Disallow implicit this as any
alwaysStrict Emit "use strict"

(2) Understanding Each Point

TYPESCRIPT
// strictNullChecks: true
let name: string = null;    // ❌ null Cannot be assigned string
let name2: string | null = null;  // ✅ Explicit Declaration

// noImplicitAny: true
function greet(name) {      // ❌ The parameter is implicitly set to any
  return name;
}
function greet2(name: string) {  // ✅ Explicit Annotation
  return name;
}

// strictPropertyInitialization: true
class User {
  name: string;    // ❌ Property not initialized
  age: number = 0; // ✅ Has an initial value
}
📌 Recommendation: Enable strict for all new projects. It is the cornerstone of TypeScript's type safety—although it may require a bit more effort to add type annotations initially, it helps prevent a large number of runtime errors.

▶ Example: Comparison Before and After Strict Mode

TYPESCRIPT
// strict: false — the following code does not generate any errors, but it may crash during execution.
let name: string = null as any;    // Runtime name.toUpperCase() Breakdown
function greet(user) {             // user Implicit any
  return user.name;                // No type checking
}

// strict: true — captured at compile time
let name2: string | null = null;   // ✅ Must be explicitly declared null
function greet2(user: { name: string }) {  // ✅ Parameters must be labeled
  return user.name;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Compile error — strict mode catches null and implicit any issues


4. Module and Path Configuration

(1) Path Mapping

JSON
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@utils/*": ["src/utils/*"],
      "@components/*": ["src/components/*"]
    }
  }
}

(2) resolveJsonModule

JSON
{
  "compilerOptions": {
    "resolveJsonModule": true,
    "esModuleInterop": true
  }
}
TYPESCRIPT
// Import Allowed JSON Documents
import config from "./config.json";
console.log(config.port);  // ✅

(3) allowJs with checkJs

JSON
{
  "compilerOptions": {
    "allowJs": true,    // Allow compilation JS Documents
    "checkJs": false    // Do not check JS File Type(Compile Only)
  }
}
💡 Purpose: When gradually migrating a JS project to TS, start by enabling allowJs to allow TS and JS to coexist, then gradually add types.



5. Code Quality Options

JSON
{
  "compilerOptions": {
    "noUnusedLocals": true,       // Error: Unused local variables
    "noUnusedParameters": true,   // Error: Unused function parameters
    "noImplicitReturns": true,    // Error: Function branch does not return a value
    "noFallthroughCasesInSwitch": true,  // Error: switch fallthrough
    "forceConsistentCasingInFileNames": true  // File names must be case-sensitive
  }
}

(1) Demo

TYPESCRIPT
// noUnusedLocals: true
let unused = 42;    // ❌ Unused variables

// noUnusedParameters: true
function handler(event: Event) {  // ❌ event Unused
  console.log("Trigger");
}
// Fix: Use _ prefix tag
function handler2(_event: Event) {  // ✅ _ The prefix does not cause an error
  console.log("Trigger");
}

// noImplicitReturns: true
function getGrade(score: number): string {
  if (score >= 90) return "A";
  if (score >= 80) return "B";
  // ❌ Missing else Branched return
}

// noFallthroughCasesInSwitch: true
switch (action) {
  case "create":
    createItem();
    // ❌ Missing break——case Penetration
  case "update":
    updateItem();
    break;
}


6. Common Configuration Templates

(1) Node.js Backend Project

JSON
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "moduleResolution": "node",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

(2) React Front-End Project (Vite)

JSON
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

(3) Library Projects (Publishing npm Packages)

JSON
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ESNext",
    "moduleResolution": "node",
    "declaration": true,
    "declarationDir": "./dist/types",
    "outDir": "./dist/esm",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

▶ Example: Target and Module Configuration Effects

TYPESCRIPT
// The same source code compiles differently based on target/module settings
async function fetchData(): Promise<string> {
  let response = await Promise.resolve("hello");
  return response.toUpperCase();
}

export function greet(name: string): string {
  return `Hello, ${name}!`;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Compilation output varies by target/module — see explanations below

With "target": "ES5", async/await compiles to a verbose state machine; with "target": "ES2020", it stays as native async/await. With "module": "CommonJS", exports become exports.greet = greet; with "module": "ESNext", they remain as export function greet.

▶ Example: Strict Null Checks in Practice

TYPESCRIPT
// strictNullChecks: true prevents common null bugs
interface User { name: string; email: string | null; }

function getDisplayName(user: User): string {
  // return user.email.toLowerCase(); // ❌ Object is possibly null
  return user.email ? user.email.toLowerCase() : user.name; // ✅
}

function findUser(id: number): User | null {
  return id > 0 ? { name: "Alice", email: "a@b.com" } : null;
}

let user = findUser(1);
// console.log(user.name); // ❌ user is possibly null
if (user) {
  console.log(user.name); // ✅ narrowed to User
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Alice

❓ FAQ

Q Does strict make code harder to write?
A It may require more type annotations initially (especially for null checks), but in the long run, it significantly reduces runtime bugs. We recommend enabling strict from the start—once you get used to it, you’ll actually find it awkward not to use it. If your project is already large, you can enable it gradually: first enable noImplicitAny, then strictNullChecks, and finally enable strict fully.
Q What is noEmit? Why was the Vite project created?
A noEmit: true allows TypeScript to perform only type checking without outputting JS files. The Vite project uses Vite (esbuild) for compilation and bundling, while tsc is responsible only for type checking—so there’s no need for tsc to output files. Use tsc --noEmit for type checking in CI, and let Vite handle real-time compilation during development.
Q Should skipLibCheck be enabled?
A We recommend enabling it. skipLibCheck skips type checking for .d.ts files, which can significantly speed up compilation. The downside is that it may miss errors in third-party type declarations—but the risk is extremely low (the @types package is community-reviewed). Enabling skipLibCheck in large projects can save 30% or more in compilation time.
Q What is the purpose of using extends for configuration inheritance?
A When a project has multiple tsconfig files (e.g., frontend, Node scripts, and tests), use extends to share the base configuration and override only the differences. tsconfig.node.json can extends tsconfig.json, modifying only options such as target and module. This avoids configuration duplication.

📖 Summary

📝 Exercises

  1. Basic Exercise (Difficulty ⭐): Use tsc --init to generate the default tsconfig.json file, change the target to ES2020, enable strict, and set outDir to dist. Create a simple TypeScript file, compile it, and verify that it works.
  2. Advanced Exercise (Difficulty ⭐⭐): Configure a tsconfig.json file that supports the path alias @/*src/*. Create src/utils/math.ts and src/main.ts, and use the alias to import functions from math.ts into main.ts.
  3. Challenge (Difficulty: ⭐⭐⭐): Design a configuration hierarchy for a monorepo project—base tsconfig.base.json (shared options), packages/app/tsconfig.json (extends base, React frontend), and packages/server/tsconfig.json (extends base, Node backend)—and use references to link the two subprojects.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏