1. Quick Start
TypeScript is a strongly-typed programming language that builds on JavaScript by adding static type definitions, enabling developers to catch errors at compile time rather than at runtime. Created by Microsoft, TypeScript compiles to plain JavaScript and runs anywhere JavaScript runs — browsers, Node.js, Deno, and more.
Key features:
- Static type checking that catches bugs before code ships
- Full JavaScript interoperability — every valid JS file is valid TS
- Rich IDE support with IntelliSense, refactoring, and navigation
- Modern ECMAScript feature support with downlevel compilation
- Declaration files (
.d.ts) for typing JavaScript libraries - Project references for monorepo and multi-project builds
- Watch mode for instant recompilation on file changes
- Incremental compilation for fast rebuilds
Prerequisites: Node.js 14.17 or later
Install and compile your first file:
npm install -g typescript
Create a file hello.ts:
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("World"));
Compile and run:
tsc hello.ts
node hello.js
Hello, World!
Tip
Skip the global install — most projects use a local
typescriptdevDependency and runnpx tscinstead. This pins your project to a specific TypeScript version.
What to try next: Initialize a project configuration with tsc --init, explore strict mode, or set up watch mode with tsc --watch.
2. Installation
System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Node.js | 14.17 | 22.x (LTS) |
| npm | 6.x | 8.x+ |
| Disk space | ~50 MB | ~50 MB |
| OS | Windows, macOS, Linux | Any |
Installation Methods
npm (recommended)
npm install --save-dev typescript
yarn
yarn add --dev typescript
pnpm
pnpm add -D typescript
Global install
npm install -g typescript
Important
Install TypeScript as a devDependency in your project rather than globally. This ensures all team members and CI pipelines use the same version.
Post-Install Verification
npx tsc --version
Version 6.0.0
Verify the language server is available:
npx tsserver --version
Install Troubleshooting
Error: tsc: command not found
Cause: TypeScript is installed locally but not on PATH.
Solution:
- Use
npx tscinstead oftsc - Or add an npm script:
"build": "tsc"inpackage.json - Or install globally:
npm install -g typescript
Prevention: Always use npx tsc for local installations.
Error: Cannot find module 'typescript'
Cause: TypeScript is not installed in the current project.
Solution:
- Run
npm install --save-dev typescript - Verify with
npx tsc --version
Prevention: Include typescript in devDependencies.
Error: npm ERR! code EACCES
Cause: Insufficient permissions for global install.
Solution:
- Use
sudo npm install -g typescript(Linux/macOS) - Or configure npm to use a user-level global directory
- Or use
npx tscwithout global install
Prevention: Use local installs or configure npm prefix.
Error: engine "node" is incompatible
Cause: Node.js version is below the minimum requirement of 14.17.
Solution:
- Update Node.js:
nvm install --ltsor download from nodejs.org - Verify:
node --version
Prevention: Use a Node.js version manager (nvm, fnm, Volta).
3. Configuration
TypeScript projects are configured through tsconfig.json, a JSON file at the project root that specifies compiler options, file inclusion/exclusion patterns, and project references.
Initialize a Configuration
npx tsc --init
This generates a tsconfig.json with recommended defaults:
{
"compilerOptions": {
"module": "nodenext",
"target": "esnext",
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"types": []
}
}
Common Option Combinations
| Scenario | Key Options |
|---|---|
| Node.js app | "module": "nodenext", "target": "esnext", "types": ["node"] |
| React frontend | "module": "esnext", "target": "es2020", "jsx": "react-jsx" |
| Library | "declaration": true, "declarationMap": true, "outDir": "./dist" |
| Strict checking | "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true |
| Monorepo | "composite": true, "references": [...], "declarationMap": true |
Essential Compiler Options
| Option | Default | Description |
|---|---|---|
target |
es5 |
ECMAScript version for output |
module |
varies | Module system (nodenext, esnext, commonjs) |
strict |
false |
Enable all strict type-checking options |
outDir |
(same as source) | Output directory for compiled files |
rootDir |
(inferred) | Root directory of source files |
declaration |
false |
Generate .d.ts declaration files |
sourceMap |
false |
Generate .js.map source map files |
jsx |
(none) | JSX support (react, react-jsx, preserve) |
lib |
(target-dependent) | Library files to include in compilation |
skipLibCheck |
false |
Skip type checking of declaration files |
Tip
Start with
"strict": truefor new projects. It enablesstrictNullChecks,strictFunctionTypes,strictBindCallApply,strictPropertyInitialization,noImplicitAny,noImplicitThis,alwaysStrict, anduseUnknownInCatchVariablesall at once.
File Inclusion
{
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.spec.ts"]
}
| Property | Purpose |
|---|---|
include |
Glob patterns for files to compile |
exclude |
Glob patterns to skip (defaults to node_modules, bower_components, jspm_packages, outDir) |
files |
Explicit file list (no globs) |
Note
For the full configuration reference with every compiler option, see the Admin Guide § Configuration Reference.
4. Core Usage
Compiling TypeScript
Compile a project (uses tsconfig.json):
npx tsc
Compile specific files:
npx tsc file1.ts file2.ts
# Output: file1.js, file2.js in the same directory
Compile with inline options:
npx tsc --target es2020 --module nodenext --outDir dist src/index.ts
Warning
When you pass files directly to
tsc, thetsconfig.jsonfile is ignored. Usetsc -p tsconfig.jsonor justtsc(without file arguments) to use your config.
Type-check only (no output):
npx tsc --noEmit
This is useful in CI pipelines where a separate bundler (esbuild, Vite, webpack) handles the actual compilation.
Show the resolved configuration:
npx tsc --showConfig
Watch Mode
Watch mode recompiles automatically when files change:
npx tsc --watch
[12:00:00 AM] Starting compilation in watch mode...
[12:00:01 AM] Found 0 errors. Watching for file changes.
Tip
Combine
--watchwith--preserveWatchOutputto prevent the terminal from being cleared on each recompilation.
Watch Mode Environment Variables
| Variable | Purpose |
|---|---|
TSC_WATCHFILE |
Override the file watching strategy |
TSC_WATCHDIRECTORY |
Override the directory watching strategy |
TSC_NONPOLLING_WATCHER |
Use a non-polling watcher when available |
Incremental Compilation
Enable incremental builds for faster recompilation:
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./.tsbuildinfo"
}
}
TypeScript saves a .tsbuildinfo file that records the state of the last compilation. Subsequent builds only recompile changed files.
Project References
For monorepos or multi-package projects, use project references to compile interdependent projects efficiently:
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true
},
"references": [
{ "path": "../shared" },
{ "path": "../utils" }
]
}
Build all referenced projects:
npx tsc --build
# Builds projects in dependency order
| Build Flag | Purpose |
|---|---|
--build (-b) |
Build project references in dependency order |
--clean |
Delete outputs of all referenced projects |
--dry |
Show what would be built without building |
--force |
Force rebuild even if outputs are up to date |
--verbose |
Show detailed build information |
Note
Projects using
--buildmode must set"composite": trueand"declaration": truein theirtsconfig.json.
Declaration Files
Generate type declaration files (.d.ts) for libraries:
npx tsc --declaration --emitDeclarationOnly --outDir types
For isolated declaration emit (faster, per-file):
{
"compilerOptions": {
"declaration": true,
"isolatedDeclarations": true
}
}
Source Maps
Enable source maps to debug TypeScript directly:
{
"compilerOptions": {
"sourceMap": true,
"declarationMap": true
}
}
| Option | Output | Use Case |
|---|---|---|
sourceMap |
.js.map |
Debug JS back to TS source |
inlineSourceMap |
Embedded in .js |
Single-file debug output |
declarationMap |
.d.ts.map |
Navigate from declaration to source |
sourceRoot |
(path) | Override source root in source maps |
mapRoot |
(path) | Override map file location |
5. Common Tasks
Task 1: Migrate a JavaScript Project to TypeScript
Goal: Gradually adopt TypeScript in an existing JavaScript codebase.
Steps:
-
Install TypeScript:
npm install --save-dev typescript @types/node -
Create
tsconfig.jsonwith permissive settings:{ "compilerOptions": { "allowJs": true, "checkJs": false, "target": "esnext", "module": "nodenext", "outDir": "./dist", "strict": false }, "include": ["src"] } -
Rename files from
.jsto.tsone at a time -
Fix type errors as they appear
-
Gradually enable strict options:
"noImplicitAny": true, "strictNullChecks": true
Verify: npx tsc --noEmit reports zero errors.
Tip
Use
// @ts-ignoreor// @ts-expect-erroras temporary escape hatches during migration. Remove them once proper types are added.
Task 2: Set Up TypeScript with a Bundler
Goal: Use TypeScript with esbuild, Vite, or webpack for frontend development.
Steps:
-
Configure TypeScript for type-checking only:
{ "compilerOptions": { "noEmit": true, "isolatedModules": true, "verbatimModuleSyntax": true, "moduleDetection": "force", "module": "esnext", "target": "esnext", "strict": true } } -
Add scripts to
package.json:{ "scripts": { "typecheck": "tsc --noEmit", "typecheck:watch": "tsc --noEmit --watch" } } -
Let the bundler handle compilation; TypeScript handles type checking
Verify: npm run typecheck passes with no errors.
Important
When using
isolatedModules, every file must be independently parseable. This means noconst enumacross files, nonamespacemerging, and every file must have at least one import or export.
Task 3: Type-Check JavaScript Files with JSDoc
Goal: Get TypeScript's type checking benefits without renaming files.
Steps:
-
Enable JS checking in
tsconfig.json:{ "compilerOptions": { "allowJs": true, "checkJs": true, "noEmit": true }, "include": ["src/**/*.js"] } -
Add JSDoc type annotations to your JavaScript:
/** * @param {string} name * @returns {string} */ function greet(name) { return `Hello, ${name}!`; } -
Run the type checker:
npx tsc --noEmit
Verify: Type errors are reported for JSDoc-annotated code.
Task 4: Configure Path Aliases
Goal: Use import aliases like @app/utils instead of relative paths.
Steps:
-
Add
pathstotsconfig.json:{ "compilerOptions": { "baseUrl": ".", "paths": { "@app/*": ["src/*"], "@lib/*": ["lib/*"] } } } -
Use in code:
import { helper } from "@app/utils";
Warning
tscdoes NOT rewrite path aliases in output. Your bundler or a runtime plugin (liketsconfig-paths) must resolve them. There is active discussion about deprecatingbaseUrl(see community issue #62207).
Task 5: Generate API Documentation Types
Goal: Export declaration files for a library.
Steps:
-
Configure for library output:
{ "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist" }, "include": ["src"] } -
Set
package.jsonentry points:{ "main": "./dist/index.js", "types": "./dist/index.d.ts" } -
Build declarations:
npx tsc
Verify: .d.ts files exist in ./dist and IDE navigation works from consuming projects.
Task 6: Set Up Monorepo with Project References
Goal: Compile interdependent packages efficiently.
Steps:
-
Create a root
tsconfig.json:{ "files": [], "references": [ { "path": "packages/shared" }, { "path": "packages/app" } ] } -
Each package sets
"composite": true:{ "compilerOptions": { "composite": true, "declaration": true, "outDir": "./dist", "rootDir": "./src" }, "references": [{ "path": "../shared" }] } -
Build all:
npx tsc --build -
Clean all:
npx tsc --build --clean
Verify: npx tsc --build --dry shows the correct build order.
Task 7: Use TypeScript with React (JSX)
Goal: Configure TypeScript for React development.
Steps:
-
Install dependencies:
npm install --save-dev typescript @types/react @types/react-dom -
Configure
tsconfig.json:{ "compilerOptions": { "jsx": "react-jsx", "module": "esnext", "target": "es2020", "moduleResolution": "bundler", "strict": true } } -
Write components with
.tsxextensions:interface Props { name: string; } export function Greeting({ name }: Props) { return <h1>Hello, {name}!</h1>; }
Verify: npx tsc --noEmit passes.
| JSX Option | Output | Use Case |
|---|---|---|
react-jsx |
_jsx() calls (React 17+) |
Modern React apps |
react |
React.createElement() |
Legacy React |
preserve |
Keep JSX as-is | Bundler handles transform |
react-native |
Keep JSX as-is | React Native |
Task 8: Enable Strict Null Checks Incrementally
Goal: Adopt strictNullChecks in a large existing codebase.
Steps:
-
Enable the flag:
{ "compilerOptions": { "strictNullChecks": true } } -
Fix errors file by file — common patterns:
// Before: error TS2532 — Object is possibly 'undefined' const len = arr.length; // After: null guard const len = arr?.length ?? 0; -
Use
// @ts-expect-errorfor known issues you'll fix later
Verify: Error count decreases with each file fixed.
Task 9: Use TypeScript with ESLint
Goal: Lint TypeScript code with type-aware rules.
Steps:
-
Install:
npm install --save-dev eslint typescript-eslint -
Configure
eslint.config.mjs:import tseslint from "typescript-eslint"; export default tseslint.config( ...tseslint.configs.recommended, { languageOptions: { parserOptions: { projectService: true, }, }, } ); -
Run:
npx eslint .
Verify: ESLint reports type-aware rule violations.
Task 10: Format TypeScript Code with dprint
Goal: Use the same formatter the TypeScript project itself uses.
Steps:
- Install:
npm install --save-dev dprint @dprint/typescript - Create
dprint.json:{ "typescript": {}, "includes": ["**/*.{ts,tsx}"] } - Format:
npx dprint fmt
Verify: npx dprint check passes with no differences.
6. Troubleshooting
Diagnostic Decision Tree
Error during compilation?
├── Type error (TS2xxx) → Check types, interfaces, annotations
├── Module not found (TS2307) → Check moduleResolution, paths, installed @types
├── Config error (TS5xxx) → Check tsconfig.json syntax and option compatibility
├── Syntax error (TS1xxx) → Check for unsupported syntax or wrong target
└── Declaration error (TS4xxx) → Check export visibility and declaration settings
Error: TS2307: Cannot find module './module' or its corresponding type declarations
Cause: TypeScript cannot resolve the import. Common reasons: missing file, wrong moduleResolution, missing @types package, or incorrect paths configuration.
Solution:
- Verify the file exists at the referenced path
- Check
moduleResolutionmatches your runtime (nodenextfor Node.js,bundlerfor bundlers) - For third-party packages:
npm install --save-dev @types/package-name - For path aliases: verify
baseUrlandpathsintsconfig.json
Prevention: Use "moduleResolution": "nodenext" for Node.js projects and "moduleResolution": "bundler" for bundler-based projects.
Error: TS2322: Type 'X' is not assignable to type 'Y'
Cause: A value's type doesn't match the expected type at that position.
Solution:
- Check if a type assertion is appropriate:
value as Type - Narrow the type with a type guard:
if (typeof value === 'string') - Update the type annotation to match the actual value
- Use union types if both types are valid:
Type1 | Type2
Prevention: Enable strict mode to catch type mismatches early.
Error: TS18003: No inputs were found in config file
Cause: No .ts files match the include/files patterns in tsconfig.json.
Solution:
- Add at least one
.tsfile to your source directory - Check that
includepatterns match your file structure - Verify
excludeisn't filtering out all files
Prevention: Run tsc --showConfig to verify file inclusion patterns.
Error: TS5023: Unknown compiler option
Cause: A tsconfig.json option is misspelled or not supported in the installed TypeScript version.
Solution:
- Check the option name against the documentation
- Verify your TypeScript version supports the option:
npx tsc --version - Update TypeScript if the option was added in a newer version
Prevention: Use an IDE with TypeScript config IntelliSense for autocomplete in tsconfig.json.
Error: TS6059: File is not under 'rootDir'
Cause: A source file is outside the rootDir boundary, which breaks the output directory structure.
Solution:
- Move the file under
rootDir - Or expand
rootDirto include the file - Or add the file's directory to
includeand adjustrootDir
Prevention: Set rootDir explicitly to the common ancestor of all source files.
Error: TS1259: Module can only be default-imported using the 'esModuleInterop' flag
Cause: Importing a CommonJS module with import x from 'module' syntax without interop.
Solution:
- Enable
"esModuleInterop": trueintsconfig.json - Or use namespace import:
import * as x from 'module'
Prevention: Use "verbatimModuleSyntax": true for new projects (replaces esModuleInterop).
Error: TS2688: Cannot find type definition file for 'node'
Cause: Using Node.js APIs without the Node type definitions.
Solution:
- Install:
npm install --save-dev @types/node - Add to
tsconfig.json:"types": ["node"]
Prevention: Always install @types/node for Node.js projects.
Error: VSCode TypeScript Language Server Keeps Crashing
Cause: Large projects or circular dependencies can exhaust the language server's memory. Community reports this in issue #63405 and #63151.
Solution:
- Restart the TS server: Ctrl+Shift+P → "TypeScript: Restart TS Server"
- Increase Node.js memory: set
"typescript.tsserver.maxTsServerMemory"in VSCode settings - Exclude large generated or vendor directories from the project
- Check for circular
tsconfig.jsonreferences
Prevention: Use skipLibCheck: true and exclude test/generated files from the main project.
Warning
If the language server crashes repeatedly, check for overly complex conditional types or deeply nested generics. These can cause exponential type-checking time.
Error: TS2345: Argument of type 'X' is not assignable to parameter of type 'Y' with Generics
Cause: Generic type inference produces a narrower or different type than expected.
Solution:
- Explicitly provide type arguments:
fn<ExpectedType>(arg) - Use
satisfiesto check types without widening:const x = value satisfies Type - Check if the generic constraint is too narrow
Prevention: Test generic functions with multiple type argument combinations.
Caution
Avoid using
anyto silence type errors. Instead, useunknownand narrow the type, or use type assertions with clear justification.
7. FAQ
Q: What is the difference between interface and type?
Both define the shape of data. interface supports declaration merging (multiple declarations with the same name are combined) and extends for inheritance. type supports unions (A | B), intersections (A & B), mapped types, and conditional types. Use interface for object shapes and public APIs; use type for unions, utility types, and complex compositions.
Q: Should I use any or unknown?
Use unknown. It requires type narrowing before use, which catches bugs. any disables all type checking for that value and propagates silently. Use any only as a last resort during migration.
Q: What does strict: true actually enable?
It enables these individual flags: strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitAny, noImplicitThis, alwaysStrict, and useUnknownInCatchVariables. New flags may be added under strict in future versions.
Q: How do I check types without emitting output?
Use npx tsc --noEmit. This runs the full type checker without generating any JavaScript output. Useful in CI and when a bundler handles compilation.
Q: What is isolatedModules and should I enable it?
isolatedModules ensures each file can be independently transpiled (without cross-file information). Enable it when using a single-file transpiler like esbuild, SWC, or Babel. It disables features that require whole-program analysis, such as const enum across files and namespace merging.
Q: How do I use TypeScript with CommonJS and ESM simultaneously?
Set "module": "nodenext" and use .cts/.mts extensions to explicitly mark files. Files with .ts extension follow package.json's "type" field. This is the recommended approach for Node.js projects.
Q: What is verbatimModuleSyntax?
It enforces that import/export syntax in the source matches what appears in the output. import type { X } is erased; import { X } is preserved. This replaces the older importsNotUsedAsValues and preserveValueImports options and makes module behavior predictable.
Q: How do I handle @types packages?
TypeScript automatically discovers @types packages from node_modules/@types/. Control which are included with the types array in tsconfig.json. Set "types": [] to include none, or "types": ["node", "jest"] to include specific ones.
Q: What is the difference between moduleResolution: "node16", "nodenext", and "bundler"?
node16 and nodenext follow Node.js's native ESM resolution rules (package.json exports, .js extension in imports). nodenext always tracks the latest Node.js behavior. bundler follows bundler conventions (no extension required, supports exports but is more lenient). Use nodenext for Node.js; use bundler for Vite/webpack/esbuild projects.
Q: What is the satisfies operator?
satisfies checks that a value conforms to a type without widening the inferred type:
const palette = {
red: [255, 0, 0],
green: "#00ff00",
} satisfies Record<string, string | number[]>;
// palette.red is still number[], not string | number[]
Q: What changed in TypeScript 6.0?
TypeScript 6.0 is the current major release. Key areas of focus include module system improvements, default module setting changes (see issue #63330 for community discussion on default behavior), and the --rewriteRelativeImportExtensions flag for rewriting .ts extensions in output. Check the TypeScript 6.0 Iteration Plan (issue #63085) for the full scope.
Note
Community issue #63392 discusses updating the official TSConfig documentation at typescriptlang.org for TypeScript 6.0 changes. Some documented defaults may lag behind the actual compiler behavior.
Q: How do I speed up type checking in large projects?
- Enable
"skipLibCheck": trueto skip checking declaration files - Use project references to split large projects into smaller units
- Enable
"incremental": truefor faster subsequent builds - Exclude tests and generated code from the main compilation
- Use
--noEmitwith a fast bundler for development