1. Architecture Overview
TypeScript is a statically-typed superset of JavaScript that compiles to plain JavaScript. It consists of three major subsystems: a compiler (tsc) that performs type checking and code emission, a language service that powers IDE features like IntelliSense and refactoring, and a language server (tsserver) that exposes the language service over a JSON-based protocol to editors.
Architecture Diagram
┌─────────────────────────────────────┐
│ tsconfig.json │
│ (project configuration) │
└──────────────┬──────────────────────┘
│
┌─────────────────────────────────┼─────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌───────────────────┐ ┌─────────────────┐
│ tsc (CLI) │ │ Language Service │ │ tsserver │
│ src/tsc/ │ │ src/services/ │ │ src/server/ │
│ │ │ │ │ src/tsserver/ │
│ executeCommand │ │ completions │ │ │
│ Line() │ │ diagnostics │◄────────►│ Session │
│ │ │ refactoring │ │ (JSON protocol) │
│ │ │ navigation │ │ │
└────────┬────────┘ │ formatting │ │ Projects │
│ │ code fixes │ │ (configured, │
│ └────────┬───────────┘ │ inferred, │
│ │ │ external) │
│ ┌────────────────┘ └─────────────────┘
│ │
▼ ▼
┌───────────────────────────────────────────┐
│ Compiler Core │
│ src/compiler/ │
│ │
│ Source Text │
│ │ │
│ ▼ │
│ Scanner (scanner.ts) │
│ │ tokens │
│ ▼ │
│ Parser (parser.ts) │
│ │ AST (SourceFile) │
│ ▼ │
│ Binder (binder.ts) │
│ │ Symbols + Flow graph │
│ ▼ │
│ Checker (checker.ts) │
│ │ Type-checked AST │
│ ▼ │
│ Emitter (emitter.ts) │
│ │ + Transformers (transformers/) │
│ ▼ │
│ Output (.js, .d.ts, .map) │
└───────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────┐
│ Standard Library (src/lib/) │
│ lib.es5.d.ts, lib.es2015.d.ts, │
│ lib.dom.d.ts, lib.esnext.d.ts, ... │
│ (107 declaration files) │
└───────────────────────────────────────────┘
Component Inventory
| Component | Path | Role |
|---|---|---|
| Compiler core | src/compiler/ (36 files, 3.3M chars) |
Scanner, parser, binder, checker, emitter, transformers, module resolution, program management |
| Language service | src/services/ (38 files, 1.6M chars) |
IDE features: completions, diagnostics, refactoring, navigation, formatting, code fixes |
| Language server | src/server/ (13 files, 789K chars) |
tsserver: session management, project management, protocol handlers |
| Server entry | src/tsserver/ (3 files, 33K chars) |
Node.js tsserver entry point, IPC setup, logging |
| CLI entry | src/tsc/ (1 file, 584 chars) |
tsc command-line entry point |
| Library API | src/typescript/ (1 file, 638 chars) |
Public API re-export entry point |
| Standard library | src/lib/ (107 files, 565K chars) |
Built-in type definitions (ES5–ESNext, DOM, WebWorker, etc.) |
| Typings installer | src/typingsInstaller/ + src/typingsInstallerCore/ |
Automatic @types package discovery and installation |
| JS typing | src/jsTyping/ (3 files, 25K chars) |
Type acquisition heuristics for JavaScript files |
| Watch guard | src/watchGuard/ (1 file, 737 chars) |
Subprocess that tests if fs.watch is safe for a directory |
| Deprecated compat | src/deprecatedCompat/ (2 files, 9.2K chars) |
Shims for deprecated API functions |
| Test harness | src/harness/ (23 files, 752K chars) |
Test infrastructure: fourslash, baselines, virtual file system |
| Test runner | src/testRunner/ (6 files, 68K chars) |
Mocha-based test execution, parallel worker |
Technology Stack
| Layer | Technology |
|---|---|
| Language | TypeScript (self-hosted) |
| Runtime | Node.js ≥ 14.17 |
| Build | hereby (task runner), esbuild (bundling) |
| Testing | Mocha, chai, custom fourslash test framework |
| Linting | ESLint with typescript-eslint, custom ESLint rules |
| Formatting | dprint with @dprint/typescript |
| Coverage | c8, monocart-coverage-reports |
| CI/CD | Azure Pipelines |
| Package | npm (published as typescript) |
| License | Apache-2.0 |
Note
TypeScript is self-hosted: the compiler is written in TypeScript and compiled by a previous version of itself. The
devDependenciesincludetypescript: "^6.0.2"for bootstrapping.
2. System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Node.js | 14.17 | 22.x (LTS) |
| npm | 6.x | 8.x+ |
| OS | Windows, macOS, Linux | Any |
| Memory | 512 MB | 4 GB+ (for large projects) |
| Disk | 50 MB (installed) | 100 MB+ (with build artifacts) |
Development Requirements
| Tool | Version | Purpose |
|---|---|---|
| Node.js | 22.22.0 (Volta-pinned) | Runtime and build |
| npm | 8.19.4 (Volta-pinned) | Package management |
| hereby | ≥ 1.14.0 | Task runner (replaces Gulp) |
| esbuild | ≥ 0.27.4 | Fast bundling for build |
| dprint | ≥ 0.49.1 | Code formatting |
| Mocha | ≥ 10.8.2 | Test framework |
| Playwright | ≥ 1.58.2 | Browser-based tests |
3. Configuration Reference
TypeScript configuration is defined in tsconfig.json (or jsconfig.json for JavaScript-only projects). The compiler reads this file to determine compilation options, file scope, and project structure.
Configuration Files
| File | Format | Location | Purpose |
|---|---|---|---|
tsconfig.json |
JSON with comments | Project root | Primary project configuration |
jsconfig.json |
JSON with comments | Project root | JavaScript project configuration (alias for tsconfig.json with allowJs: true) |
tsconfig.*.json |
JSON with comments | Project root | Variant configs (e.g., tsconfig.build.json, tsconfig.test.json) |
Configuration Hierarchy
Configurations support inheritance via extends:
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
}
}
Important
Relative paths in
extendsare resolved relative to the file containing theextendsproperty. The${configDir}template variable can be used in path-valued options to reference the directory of the current config file.
Compiler Options by Category
File Layout
| Option | Type | Default | Description |
|---|---|---|---|
rootDir |
string |
(inferred from inputs) | Root directory of input files; controls output directory structure |
outDir |
string |
(same as input) | Output directory for all emitted files |
outFile |
string |
(none) | Concatenate and emit output to a single file (AMD/SystemJS only) |
rootDirs |
string[] |
(none) | Virtual root directories for module resolution |
declarationDir |
string |
(same as outDir) |
Output directory for declaration files |
Environment Settings
| Option | Type | Default | Description |
|---|---|---|---|
target |
string |
es5 |
ECMAScript target version: es5, es2015–es2023, esnext |
module |
string |
varies by target | Module system: nodenext, esnext, commonjs, amd, system, umd |
moduleResolution |
string |
varies by module | Resolution strategy: nodenext, node16, bundler, node10, classic |
lib |
string[] |
(target-dependent) | Library declaration files to include |
types |
string[] |
(all @types) |
@types packages to include |
typeRoots |
string[] |
["./node_modules/@types"] |
Directories to search for type declarations |
Strict Type-Checking
| Option | Type | Default | Description |
|---|---|---|---|
strict |
boolean |
false |
Enable all strict type-checking options |
strictNullChecks |
boolean |
strict |
null and undefined are distinct types |
strictFunctionTypes |
boolean |
strict |
Contravariant function parameter checking |
strictBindCallApply |
boolean |
strict |
Check bind, call, apply argument types |
strictPropertyInitialization |
boolean |
strict |
Class properties must be initialized or declared with ! |
noImplicitAny |
boolean |
strict |
Error on expressions with implied any type |
noImplicitThis |
boolean |
strict |
Error on this with implied any type |
alwaysStrict |
boolean |
strict |
Parse in strict mode and emit "use strict" |
useUnknownInCatchVariables |
boolean |
strict |
Type catch clause variables as unknown |
exactOptionalPropertyTypes |
boolean |
false |
Differentiate between undefined and missing optional properties |
noUncheckedIndexedAccess |
boolean |
false |
Add undefined to index signature access results |
Module Options
| Option | Type | Default | Description |
|---|---|---|---|
moduleDetection |
string |
auto |
How files are treated as modules: auto, legacy, force |
esModuleInterop |
boolean |
false |
Emit interop helpers for CommonJS/ESM compatibility |
verbatimModuleSyntax |
boolean |
false |
Enforce import syntax matches output; replaces importsNotUsedAsValues |
isolatedModules |
boolean |
false |
Ensure each file can be transpiled independently |
isolatedDeclarations |
boolean |
false |
Ensure declarations can be generated per-file |
allowSyntheticDefaultImports |
boolean |
varies | Allow import x from 'module' for modules without default export |
resolveJsonModule |
boolean |
false |
Allow importing .json files |
resolvePackageJsonExports |
boolean |
varies | Use package.json exports field for resolution |
resolvePackageJsonImports |
boolean |
varies | Use package.json imports field for resolution |
allowImportingTsExtensions |
boolean |
false |
Allow .ts/.tsx in import specifiers (requires noEmit or emitDeclarationOnly) |
rewriteRelativeImportExtensions |
boolean |
false |
Rewrite .ts extensions to .js in output |
allowArbitraryExtensions |
boolean |
false |
Allow importing files with arbitrary extensions |
noUncheckedSideEffectImports |
boolean |
false |
Check that side-effect imports resolve |
Path Mapping
| Option | Type | Default | Description |
|---|---|---|---|
baseUrl |
string |
(none) | Base directory for non-relative module names |
paths |
object |
(none) | Path alias mappings (requires baseUrl or relative to tsconfig.json) |
rootDirs |
string[] |
(none) | Virtual combined directory for resolution |
Emit Options
| Option | Type | Default | Description |
|---|---|---|---|
declaration |
boolean |
false |
Generate .d.ts declaration files |
declarationMap |
boolean |
false |
Generate source maps for declarations |
emitDeclarationOnly |
boolean |
false |
Only emit declarations, not JavaScript |
sourceMap |
boolean |
false |
Generate .js.map source map files |
inlineSourceMap |
boolean |
false |
Embed source maps in .js files |
inlineSources |
boolean |
false |
Embed TypeScript source in source maps |
noEmit |
boolean |
false |
Do not emit any output files |
noEmitOnError |
boolean |
false |
Do not emit if there are type errors |
removeComments |
boolean |
false |
Strip comments from output |
importHelpers |
boolean |
false |
Import emit helpers from tslib |
downlevelIteration |
boolean |
false |
Full iterator protocol support in ES5 output |
newLine |
string |
platform | Line ending: crlf or lf |
preserveConstEnums |
boolean |
false |
Keep const enum declarations in output |
emitBOM |
boolean |
false |
Emit UTF-8 BOM |
emitDecoratorMetadata |
boolean |
false |
Emit design-type metadata for decorators |
experimentalDecorators |
boolean |
false |
Enable legacy decorator support |
JavaScript Support
| Option | Type | Default | Description |
|---|---|---|---|
allowJs |
boolean |
false |
Allow JavaScript files in the project |
checkJs |
boolean |
false |
Type-check JavaScript files |
maxNodeModuleJsDepth |
number |
0 |
Max depth to search node_modules for JS type info |
JSX
| Option | Type | Default | Description |
|---|---|---|---|
jsx |
string |
(none) | JSX support: react, react-jsx, react-jsxdev, preserve, react-native |
jsxFactory |
string |
React.createElement |
JSX factory function |
jsxFragmentFactory |
string |
React.Fragment |
JSX fragment factory |
jsxImportSource |
string |
react |
Module for JSX factory import (with react-jsx) |
Project References
| Option | Type | Default | Description |
|---|---|---|---|
composite |
boolean |
false |
Enable constraints for project references |
incremental |
boolean |
composite |
Save build state for incremental compilation |
tsBuildInfoFile |
string |
.tsbuildinfo |
Path for incremental build state file |
disableReferencedProjectLoad |
boolean |
false |
Lazy-load referenced projects |
disableSolutionSearching |
boolean |
false |
Opt out of multi-project find-references |
Completeness
| Option | Type | Default | Description |
|---|---|---|---|
skipLibCheck |
boolean |
false |
Skip type checking all .d.ts files |
skipDefaultLibCheck |
boolean |
false |
Skip type checking built-in .d.ts files |
forceConsistentCasingInFileNames |
boolean |
false |
Disallow inconsistent file name casing |
noErrorTruncation |
boolean |
false |
Show full type in error messages |
preserveSymlinks |
boolean |
false |
Do not resolve symlinks to their real path |
Watch Options
{
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
"fallbackPolling": "dynamicPriorityPolling",
"synchronousWatchDirectory": true,
"excludeDirectories": ["**/node_modules", "dist"]
}
}
| Option | Values | Description |
|---|---|---|
watchFile |
useFsEvents, useFsEventsOnParentDirectory, dynamicPriorityPolling, fixedPollingInterval, priorityPollingInterval, fixedChunkSizePolling |
File watching strategy |
watchDirectory |
useFsEvents, dynamicPriorityPolling, fixedPollingInterval, fixedChunkSizePolling |
Directory watching strategy |
fallbackPolling |
dynamicPriorityPolling, fixedInterval, priorityInterval, fixedChunkSize |
Fallback when fs events unavailable |
synchronousWatchDirectory |
boolean |
Defer watch directory notifications |
excludeDirectories |
string[] |
Directories excluded from watching |
excludeFiles |
string[] |
Files excluded from watching |
Tip
On Linux systems with many files, you may hit the inotify watch limit. Either increase it (
sysctl fs.inotify.max_user_watches=524288) or use polling-based watch strategies.
Environment Variables
| Variable | Purpose | Source |
|---|---|---|
TSC_WATCHFILE |
Override file watching strategy | src/compiler/sys.ts |
TSC_NONPOLLING_WATCHER |
Use non-polling file watcher | src/compiler/sys.ts |
TSC_WATCHDIRECTORY |
Override directory watching strategy | src/compiler/sys.ts |
TSS_LOG |
tsserver log file path and verbosity | src/tsserver/nodeServer.ts |
TSS_TRACE |
tsserver trace file path | src/tsserver/nodeServer.ts |
NODE_ENV |
When set to development, enables source maps in tsc/tsserver |
src/tsc/tsc.ts, src/tsserver/server.ts |
NODE_INSPECTOR_IPC |
Detected to identify debugger attachment | src/compiler/sys.ts |
VSCODE_INSPECTOR_OPTIONS |
Detected to identify VS Code debugger | src/compiler/sys.ts |
Important
TSS_LOGaccepts a path (e.g.,TSS_LOG="-logToFile true -file /tmp/tsserver.log -level verbose"). This is essential for diagnosing language server issues. Log levels:terse,normal,requestTime,verbose.
File Inclusion/Exclusion
| Property | Type | Default | Description |
|---|---|---|---|
include |
string[] |
["**/*"] |
Glob patterns for source files |
exclude |
string[] |
["node_modules", "bower_components", "jspm_packages", outDir] |
Glob patterns to exclude |
files |
string[] |
(none) | Explicit file list (no globs, must exist) |
4. Deployment & Scaling
Publishing TypeScript as a Package
TypeScript itself is published to npm as the typescript package. The published artifact contains:
| Directory | Contents |
|---|---|
bin/ |
tsc and tsserver CLI entry scripts |
lib/ |
Bundled compiler (typescript.js), language service, standard library .d.ts files |
lib/typescript.d.ts |
Public API type definitions |
The package.json defines:
{
"main": "./lib/typescript.js",
"typings": "./lib/typescript.d.ts",
"bin": {
"tsc": "./bin/tsc",
"tsserver": "./bin/tsserver"
}
}
Release Process
TypeScript uses Azure Pipelines for CI/CD:
- Build pipeline (
azure-pipelines.release.yml): triggers onrelease-*branches, runs tests, produces a tarball artifact - Publish pipeline (
azure-pipelines.release-publish.yml): manual trigger, publishes the tarball to npm with a tag (dev,beta,rc,latest) and creates a GitHub release
Publish tags:
| Tag | Purpose |
|---|---|
dev |
Nightly development builds |
beta |
Pre-release beta versions |
rc |
Release candidates |
latest |
Stable releases |
Embedding TypeScript
TypeScript can be used as a library:
import * as ts from "typescript";
const program = ts.createProgram(["src/index.ts"], {
target: ts.ScriptTarget.ES2020,
module: ts.ModuleKind.NodeNext,
});
const diagnostics = ts.getPreEmitDiagnostics(program);
diagnostics.forEach(d => {
console.log(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
});
The public API is exported from src/typescript/typescript.ts which re-exports all public symbols from the compiler and services.
Note
The TypeScript API is large and not all of it is documented. Many internal types are accessible but marked
@internaland may change between versions without notice.
5. Operations
Build System
TypeScript uses hereby as its task runner (replacing the legacy Gulp setup via .gulp.js compatibility shim):
npx hereby <task>
Key build tasks (from package.json scripts):
| Command | Task |
|---|---|
npm run build:compiler |
hereby local — build the compiler |
npm run build:tests |
hereby tests — build the test infrastructure |
npm run build |
Build compiler + tests |
npm run test |
hereby runtests-parallel --light=false — run all tests |
npm run lint |
hereby lint — run ESLint |
npm run format |
dprint fmt — format all source |
npm run knip |
hereby knip — detect unused exports/dependencies |
npm run clean |
hereby clean — remove build artifacts |
npm run setup-hooks |
node scripts/link-hooks.mjs — install git hooks |
Tip
Use
npm run build:tests:notypecheck(hereby tests --no-typecheck) for faster test builds when you know the types are correct.
Code Coverage
Coverage is configured via .c8rc.json:
{
"reporter": ["lcovonly", "cobertura", "v8", "v8-json", "codecov"],
"src": "src",
"include": ["src/**", "built/local/**"],
"exclude": ["**/node_modules/**"],
"mergeAsync": true
}
Language Server Operations
The tsserver language server is the backbone of IDE integration. It manages project state and responds to editor requests over a JSON-based protocol.
tsserver Command-Line Arguments
| Argument | Purpose |
|---|---|
--globalPlugins <plugins> |
Comma-separated list of global language service plugins |
--pluginProbeLocations <paths> |
Comma-separated paths to probe for plugins |
--allowLocalPluginLoads |
Allow loading plugins from node_modules local to the project |
--useSingleInferredProject |
Use a single inferred project for all open files |
--useInferredProjectPerProjectRoot |
Create separate inferred projects per root |
--suppressDiagnosticEvents |
Suppress diagnostic event notifications |
--noGetErrOnBackgroundUpdate |
Don't request errors after background project updates |
--canUseWatchEvents |
Enable editor-provided file watching events |
--cancellationPipeName <name> |
Named pipe for request cancellation |
--locale <locale> |
Display language locale |
Typings Installer Arguments
| Argument | Purpose |
|---|---|
--globalCacheLocation <path> |
Global cache for @types packages |
--npmLocation <path> |
Path to npm executable |
--validateDefaultNpmLocation |
Verify the default npm path exists |
--typingSafeListLocation <path> |
Path to typing safe list |
--typesMapLocation <path> |
Path to types map |
--logFile <path> |
Log file for typings installer |
Note
The typings installer runs as a child process of tsserver. It discovers JavaScript files that need
@typespackages and installs them automatically via npm. The types registry is atnode_modules/types-registry/index.jsonin the global cache.
6. Performance
Compilation Performance
TypeScript uses several strategies to optimize compilation speed:
| Strategy | Mechanism |
|---|---|
| Incremental compilation | .tsbuildinfo file caches dependency graph and per-file hashes; only changed files and their dependents are re-checked |
| Project references | --build mode compiles referenced projects in dependency order, reusing up-to-date outputs |
| Lazy evaluation | The checker evaluates types on demand rather than eagerly computing all types |
| Interned strings | String interning reduces memory allocation for repeated identifiers |
| Tracing | --generateTrace <dir> produces Chrome DevTools-compatible trace files for profiling |
Memory Optimization
For large projects exceeding memory limits:
- Split into smaller projects using project references
- Enable
skipLibCheckto avoid checking third-party declarations - Use
disableReferencedProjectLoadfor lazy-loading referenced projects - Limit
libto only the libraries actually needed - Exclude test and generated files from the main
tsconfig.json
Profiling
npx tsc --generateTrace trace_output
Open trace_output/trace.json in chrome://tracing or the Chrome DevTools Performance tab to identify slow phases (binding, checking, emitting).
Tip
The
--extendedDiagnosticsflag prints timing breakdown for each compilation phase (I/O, parsing, binding, checking, emitting) and memory usage.
npx tsc --extendedDiagnostics
Files: 1523
Lines of Library: 41023
Lines of Definitions: 128402
Lines of TypeScript: 89234
Nodes of Library: 172048
Nodes of Definitions: 498123
Nodes of TypeScript: 412893
Identifiers: 321034
Symbols: 198234
Types: 89102
Instantiations: 234891
Memory used: 312412K
Assignability cache size: 98234
Identity cache size: 1234
Subtype cache size: 4521
Strict subtype cache size: 2345
I/O Read time: 0.12s
Parse time: 0.45s
ResolveModule time: 0.08s
ResolveTypeReference time: 0.02s
Program time: 0.89s
Bind time: 0.23s
Check time: 2.34s
Emit time: 0.56s
Total time: 4.02s
7. Security
Supply Chain Security
TypeScript's package.json defines "browser" overrides that disable Node.js-specific modules (fs, os, path, crypto, buffer, inspector, perf_hooks, source-map-support) when TypeScript is loaded in a browser context. This prevents accidental exposure of server-side APIs.
Configuration Security
skipLibCheck: While it improves performance, it skips type checking of declaration files, which means type errors in third-party packages won't be caughtallowJs+checkJs: When enabled on untrusted JavaScript, TypeScript's JSDoc parser processes all JSDoc comments, which could contain misleading type assertionsplugins: Language service plugins run in the tsserver process with full Node.js access. Only install plugins from trusted sourcesallowLocalPluginLoads: When tsserver is started with this flag, it loads plugins fromnode_modulesrelative to the project, which could be a vector for malicious packages
Warning
Language service plugins execute arbitrary JavaScript in the editor's TypeScript process. Review any plugins before enabling
--allowLocalPluginLoadsin your editor configuration.
Source Map Security
Source maps (sourceMap, inlineSourceMap, inlineSources) can expose original TypeScript source code. In production deployments, either disable source maps or ensure they are not served publicly.
8. Developer Internals
Repository Structure
microsoft/TypeScript/
├── src/
│ ├── compiler/ # Core compiler (36 files, 3.3M chars)
│ │ ├── scanner.ts # Lexical analysis → token stream
│ │ ├── parser.ts # Syntax analysis → AST (SourceFile)
│ │ ├── binder.ts # Symbol creation + control flow graph
│ │ ├── checker.ts # Type checking (the largest file in the project)
│ │ ├── emitter.ts # Code generation orchestration
│ │ ├── transformer.ts # AST transformation pipeline
│ │ ├── transformers/ # Individual transformers (ES2015→ES5, JSX, etc.)
│ │ ├── types.ts # All AST node types and compiler types
│ │ ├── program.ts # Program creation and management
│ │ ├── sys.ts # System abstraction (file I/O, watch)
│ │ ├── commandLineParser.ts # CLI argument parsing
│ │ ├── moduleNameResolver.ts # Module resolution algorithms
│ │ ├── core.ts # Core utilities (Queue, sorting, etc.)
│ │ ├── utilities.ts # Internal utility functions
│ │ ├── utilitiesPublic.ts # Public utility functions
│ │ ├── diagnosticInformationMap.generated.ts # All diagnostic messages
│ │ ├── tracing.ts # Performance tracing
│ │ └── factory/ # AST node factory functions
│ ├── services/ # Language service (38 files, 1.6M chars)
│ │ ├── services.ts # LanguageService implementation
│ │ ├── completions.ts # IntelliSense completion provider
│ │ ├── goToDefinition.ts
│ │ ├── findAllReferences.ts
│ │ ├── rename.ts
│ │ ├── signatureHelp.ts
│ │ ├── documentHighlights.ts
│ │ ├── callHierarchy.ts
│ │ ├── inlayHints.ts
│ │ ├── navigateTo.ts
│ │ ├── navigationBar.ts
│ │ ├── organizeImports.ts
│ │ ├── outliningElementsCollector.ts
│ │ ├── smartSelection.ts
│ │ ├── formatting/ # Code formatting rules engine
│ │ │ ├── rules.ts # Formatting rule definitions
│ │ │ └── ...
│ │ ├── refactors/ # Refactoring providers
│ │ ├── codefixes/ # Code fix providers
│ │ └── classifier.ts # Semantic/syntactic classification
│ ├── server/ # Language server (13 files, 789K chars)
│ │ ├── session.ts # Request/response handler (protocol implementation)
│ │ ├── project.ts # Project types and management
│ │ ├── editorServices.ts # Editor integration services
│ │ ├── protocol.ts # Wire protocol type definitions
│ │ ├── utilitiesPublic.ts # Server utility functions
│ │ └── ...
│ ├── tsserver/ # Server entry point (3 files)
│ │ ├── server.ts # Main entry + startup
│ │ ├── nodeServer.ts # Node.js system initialization + logging
│ │ └── common.ts # Shared types
│ ├── tsc/ # CLI entry point (1 file)
│ │ └── tsc.ts # Calls ts.executeCommandLine()
│ ├── typescript/ # Library entry (1 file)
│ │ └── typescript.ts # Re-exports all public API
│ ├── lib/ # Standard library (107 .d.ts files)
│ ├── jsTyping/ # JS type acquisition
│ ├── typingsInstaller/ # @types installer (Node.js)
│ ├── typingsInstallerCore/ # @types installer core logic
│ ├── watchGuard/ # fs.watch safety check subprocess
│ ├── deprecatedCompat/ # Deprecated API shims
│ ├── harness/ # Test harness (23 files)
│ └── testRunner/ # Test runner (6 files)
├── tests/ # Test suite (80K+ files, mostly baselines)
│ ├── cases/ # Test input files
│ ├── baselines/ # Expected output baselines
│ └── lib/ # Test library stubs
├── scripts/ # Build and maintenance scripts
│ ├── eslint/ # Custom ESLint rules for the project
│ └── hooks/ # Git hooks
├── lib/ # Published library output (not in source)
├── .c8rc.json # Coverage configuration
├── .gulp.js # hereby compatibility shim
├── package.json # Package manifest
└── azure-pipelines.*.yml # CI/CD pipeline definitions
Architecture Deep Dive
Compiler Pipeline
The TypeScript compiler processes source code through five sequential phases:
1. Scanner (scanner.ts)
Converts source text into a stream of tokens. The scanner is re-entrant and supports rescanning for template literals and JSX. It handles Unicode, regular expressions, and comment parsing.
2. Parser (parser.ts)
Consumes the token stream and produces an Abstract Syntax Tree (AST). Each source file becomes a SourceFile node. The parser handles:
- Full ECMAScript grammar + TypeScript extensions (type annotations, enums, decorators, etc.)
- JSX syntax
- JSDoc comment parsing for JavaScript type checking
- Error recovery (produces a valid AST even for malformed input)
3. Binder (binder.ts)
Walks the AST and creates Symbol objects that connect declarations to their uses. The binder also constructs the control flow graph used for narrowing (type guards, null checks). Key responsibilities:
- Symbol table construction (mapping names to declarations)
- Control flow graph for type narrowing
- Container/scope identification
- Module and namespace resolution
- Export assignment tracking
4. Checker (checker.ts)
The type checker is the largest and most complex component. It performs:
- Type inference (return types, generic instantiation, contextual typing)
- Type compatibility checking (assignability, subtype, identity)
- Overload resolution
- Generic type parameter inference and constraint checking
- Control-flow-based type narrowing (
typeof,instanceof, truthiness, discriminated unions) - Excess property checking
- JSX element type checking
- Diagnostic message generation for type errors
5. Emitter (emitter.ts) + Transformers (transformer.ts, transformers/)
Converts the type-checked AST into output files. The emitter orchestrates a pipeline of transformers, each handling a specific downlevel transformation:
- TypeScript → JavaScript (strip types, transform enums)
- ES2015+ → ES5 (arrow functions, classes, destructuring, generators, async/await)
- JSX → JavaScript (createElement/jsx calls)
- Module → target format (CommonJS, AMD, SystemJS, UMD, ESM)
- Declaration emit (
.d.tsgeneration)
Module Resolution
Module resolution (moduleNameResolver.ts) implements multiple strategies:
| Strategy | Algorithm |
|---|---|
nodenext / node16 |
Node.js native ESM resolution with package.json exports/imports fields |
bundler |
Relaxed ESM resolution (no extension required, exports supported) |
node10 (formerly node) |
Legacy Node.js resolution (main field, index.js convention) |
classic |
TypeScript's original resolution (deprecated) |
Resolution steps (simplified):
- Check
pathsmappings - Check
rootDirsvirtual directories - Try file extensions:
.ts,.tsx,.d.ts,.js,.jsx - Check
package.jsonexports/main/types/typings - Check
@typespackages - Check
node_modulesup the directory tree
Program and Project Management
The Program object (program.ts) represents a complete compilation unit:
- Resolves the full set of source files from
tsconfig.json - Creates and manages the
SourceFileinstances - Coordinates the checker and emitter
- Handles incremental build state (
.tsbuildinfo) - Manages project references and composite builds
The sys module (sys.ts) abstracts file system operations, enabling TypeScript to run in different environments (Node.js, browser, virtual file systems for testing).
Module Reference
src/compiler/types.ts
Defines the complete TypeScript AST type hierarchy. Contains:
SyntaxKindenum (all node types)- AST node interfaces (
Node,Statement,Expression,Declaration, etc.) - Type system interfaces (
Type,Symbol,Signature) CompilerOptionsinterfaceDiagnostictypesSourceFileinterface
src/compiler/core.ts
Core utility functions used throughout the compiler:
- Array manipulation (
map,filter,flatMap,some,every) Queuedata structure- String utilities
- Assertion helpers via
Debug - Memoization utilities
src/compiler/commandLineParser.ts
Parses CLI arguments and tsconfig.json files:
parseCommandLine()— parsetscargumentsparseJsonConfigFileContent()— parsetsconfig.jsonconvertCompilerOptionsFromJson()— JSON toCompilerOptionsgenerateTSConfig()— produce defaulttsconfig.json(for--init)- Contains the authoritative list of all compiler options with their types, defaults, categories, and descriptions
src/compiler/sys.ts
System abstraction layer:
- File reading/writing
- Directory operations
- File watching (
watchFile,watchDirectory) - Environment variable access
- Process management
- Supports multiple watch strategies (fs events, polling variants)
src/services/services.ts
The LanguageService interface and its implementation. Key methods:
| Method | Purpose |
|---|---|
getCompletionsAtPosition() |
IntelliSense completions |
getCompletionEntryDetails() |
Detailed completion info |
getSemanticDiagnostics() |
Type errors |
getSyntacticDiagnostics() |
Parse errors |
getSuggestionDiagnostics() |
Suggestions (unused vars, etc.) |
getDefinitionAtPosition() |
Go to definition |
getReferencesAtPosition() |
Find all references |
getRenameInfo() / findRenameLocations() |
Symbol rename |
getSignatureHelpItems() |
Function signature help |
getQuickInfoAtPosition() |
Hover information |
getCodeFixesAtPosition() |
Quick fixes for diagnostics |
getApplicableRefactors() |
Available refactorings |
getEditsForRefactor() |
Apply a refactoring |
getFormattingEditsForRange() |
Format code |
organizeImports() |
Sort and remove unused imports |
getOutliningSpans() |
Code folding regions |
getDocumentHighlights() |
Symbol highlighting |
getNavigationBarItems() |
Navigation bar structure |
getNavigateToItems() |
Go to symbol search |
getCallHierarchyIncomingCalls() |
Call hierarchy |
provideInlayHints() |
Inlay hints (parameter names, return types) |
src/services/formatting/
The formatting engine, documented in its own README:
- Formatting decisions are rule-based (
rules.tscontains the full rule set) - Rules specify spacing/indentation between pairs of AST nodes
- The formatter is NOT publicly exported; it's only accessible through the language service
- Used by all language service operations that insert or modify code
src/server/session.ts
The tsserver session handles the JSON protocol between editors and the language service:
- Registers command handlers for all protocol commands
- Maps protocol requests to language service API calls
- Handles request cancellation
- Manages asynchronous operations (semantic diagnostics, project loading)
src/server/project.ts
Defines project types:
| Project Type | Purpose |
|---|---|
ConfiguredProject |
Backed by a tsconfig.json file |
InferredProject |
Created for files not in any tsconfig.json |
ExternalProject |
Created by external tools (e.g., IDEs with custom project models) |
AutoImportProviderProject |
Virtual project for auto-import suggestions from node_modules |
Code Patterns and Conventions
| Pattern | Convention |
|---|---|
| Module organization | Barrel re-exports via _namespaces/ directories |
| Immutability | AST nodes are read-only after creation; modifications via factory functions |
| Error handling | Debug.assert() / Debug.fail() for invariants; diagnostics for user-facing errors |
| Internal marking | /** @internal */ JSDoc tag for non-public API |
| Compilation model | Self-hosted: TypeScript compiles itself; devDependencies includes typescript for bootstrapping |
| Build output | built/local/ for development builds; lib/ for published output |
| Test baselines | Expected output files in tests/baselines/reference/; "accept baselines" to update |
| Source targets | Development builds target ES2020 with NodeNext modules |
| String interning | Heavy use of __String branded type for interned identifier text |
Testing Strategy
TypeScript uses a multi-layered testing approach:
1. Compiler baseline tests (src/testRunner/compilerRunner.ts)
- Conformance tests (
tests/cases/conformance/): ECMAScript spec conformance - Compiler tests (
tests/cases/compiler/): regression tests for specific bugs - Each test is a
.tsfile; output is compared against reference baselines
2. Fourslash tests (src/harness/fourslashImpl.ts)
- Language service integration tests
- Use a special markup syntax with markers (
/**/) and annotations - Test completions, go-to-definition, refactoring, code fixes, formatting
- Each test file defines both the source code and expected behavior
3. Project tests
- Test
tsconfig.jsonparsing and resolution - Test project references and composite builds
- Test build mode (
--build) behavior
4. Unit tests (src/testRunner/unittests/)
- Test individual components (config parsing, services, etc.)
- Standard Mocha describe/it structure
5. Parallel test execution (src/testRunner/parallel/)
- Worker-based parallel test runner
- Distributes test files across multiple Node.js workers
- Custom Mocha mixins for timeout and clone support
Note
The test suite contains 80,000+ files, with the vast majority being baseline reference files (expected outputs). The actual source code under
src/is approximately 250 files totaling ~7MB.
Potential Improvements
Based on source analysis and community issues:
-
Module default behavior in v6: Community issue #63330 discusses that the default
modulesetting in TypeScript 6.0 may not beesnextas expected. This transition area may need documentation updates. -
rewriteRelativeImportExtensionsfor declarations: Issue #61037 notes thattscdoesn't rewrite extensions in emitted declaration files even whenrewriteRelativeImportExtensionsis enabled. This is a known limitation. -
baseUrldeprecation discussion: Issue #62207 proposes deprecatingbaseUrlin favor ofpathswith relative resolution. This would affect many existing configurations. -
Language server stability: Issues #63405 and #63151 report recurring language server crashes, particularly on large projects. Memory management and complex type computation are contributing factors.
-
Error message clarity: Issue #63206 reports confusing error messages (TS2322 vs TS2741) for certain property assignment scenarios. Error message quality is an ongoing area of improvement.
Contributing
Setup:
git clone https://github.com/microsoft/TypeScript.git
cd TypeScript
npm install
npm run setup-hooks
npm run build
Development workflow:
- Make changes in
src/ - Build:
npm run build:compiler - Test:
npm test - Lint:
npm run lint - Format:
npm run format
Running specific tests:
npx hereby runtests --tests=<test-name-regex>
Updating baselines after intentional changes:
npx hereby baseline-accept
Caution
Always review baseline changes carefully before accepting. Baseline diffs can reveal unintended behavioral changes that affect downstream users.
Key conventions for contributors:
- All code is TypeScript (self-hosted)
- Use
Debug.assert()for invariants, notthrow - Mark non-public API with
/** @internal */ - Add baseline tests for compiler changes, fourslash tests for language service changes
- The codebase uses
hereby(not Gulp) for build tasks - Formatting is enforced by dprint; run
npm run formatbefore committing - Custom ESLint rules in
scripts/eslint/enforce project-specific patterns
9. Integration Points
Editor Integration
TypeScript integrates with editors through tsserver, which communicates via a JSON-based protocol over stdin/stdout:
| Editor | Integration Method |
|---|---|
| VS Code | Built-in TypeScript extension uses tsserver directly |
| Vim/Neovim | Via LSP clients (nvim-lspconfig, coc.nvim) |
| Sublime Text | LSP package with TypeScript configuration |
| JetBrains IDEs | Built-in TypeScript support (uses own parser + tsserver for some features) |
| Emacs | Via lsp-mode or eglot |
Language Service Plugin API
Plugins extend the language service with custom behavior:
function init(modules: { typescript: typeof ts }): ts.server.PluginModule {
return {
create(info: ts.server.PluginCreateInfo) {
const proxy = Object.create(null);
for (const k of Object.keys(info.languageService)) {
proxy[k] = (info.languageService as any)[k];
}
// Override methods as needed
proxy.getCompletionsAtPosition = (fileName, position, options) => {
const prior = info.languageService.getCompletionsAtPosition(fileName, position, options);
// Modify completions...
return prior;
};
return proxy;
},
};
}
export = init;
Configure in tsconfig.json:
{
"compilerOptions": {
"plugins": [
{ "name": "my-typescript-plugin" }
]
}
}
Build Tool Integration
| Tool | Integration |
|---|---|
| esbuild | --loader:.ts=ts (no type checking; use tsc --noEmit separately) |
| Vite | Built-in TypeScript support via esbuild |
| webpack | ts-loader or babel-loader with @babel/preset-typescript |
| Rollup | @rollup/plugin-typescript |
| SWC | @swc/core with TypeScript support (transpile-only) |
| Babel | @babel/preset-typescript (transpile-only) |
Note
Bundlers and transpilers like esbuild, SWC, and Babel perform transpilation only — they strip type annotations without checking them. Always run
tsc --noEmitseparately for type safety.
Programmatic API
Key entry points for embedding TypeScript:
import * as ts from "typescript";
// Create a program from files
const program = ts.createProgram(fileNames, compilerOptions);
// Parse a single file
const sourceFile = ts.createSourceFile(
"example.ts",
sourceCode,
ts.ScriptTarget.Latest
);
// Create a language service
const service = ts.createLanguageService(host);
// Parse tsconfig.json
const config = ts.readConfigFile("tsconfig.json", ts.sys.readFile);
const parsed = ts.parseJsonConfigFileContent(config.config, ts.sys, ".");