RepoPilotOpen in app →

microsoft/TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

GO

Healthy across the board

  • Last commit 1d ago
  • 5 active contributors
  • Distributed ownership (top contributor 46%)
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • Small team — 5 top contributors

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Embed this verdict

[![RepoPilot: GO](https://repopilot.app/api/badge/microsoft/typescript)](https://repopilot.app/r/microsoft/typescript)

Paste into your README — the badge live-updates from the latest cached analysis.

Onboarding doc

Onboarding: microsoft/TypeScript

Generated by RepoPilot · 2026-05-04 · Source

Verdict

GO — Healthy across the board

  • Last commit 1d ago
  • 5 active contributors
  • Distributed ownership (top contributor 46%)
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Small team — 5 top contributors

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

TL;DR

This is the official Microsoft TypeScript compiler and language service — a statically-typed superset of JavaScript that adds optional type annotations, interfaces, generics, and advanced type inference, then emits clean JavaScript. The compiler (tsc) transforms .ts/.tsx source into .js output targeting multiple ECMAScript versions, while the language service powers editor tooling (autocomplete, refactoring, go-to-definition) used by VS Code and other IDEs. Single-package repo: the entire compiler, language service, and standard library live under src/ (not shown but implied by the ~129 MB TypeScript codebase), compiled into lib/ for distribution. Build orchestration is handled by Herebyfile.mjs (a Hereby-based task runner), with bin/tsc and bin/tsserver as the CLI entry points and lib/typescript.js as the public API.

Who it's for

Two audiences: (1) JavaScript/TypeScript application developers who need a well-typed JavaScript toolchain and contribute bug reports or small fixes; (2) compiler engineers and language service contributors who work on type inference, emit logic, checker correctness, or language server protocol features. As of v6/7.0 transition, most feature work has moved to the Go rewrite at microsoft/TypeScript-go, so current contributors focus narrowly on crash fixes and regressions.

Maturity & risk

Extremely mature — TypeScript has been in active development since ~2012, is the de facto standard typed JavaScript toolchain, and has tens of thousands of GitHub stars. The repo has comprehensive .github/workflows/ci.yml-based CI with mocha tests, baselines, and c8 coverage. Commits are recent, though the README explicitly notes that new feature work is paused pending TypeScript 7.0 completion in the Go rewrite.

Very low risk for consumption: it is Microsoft-backed, Apache-2.0 licensed, and has no runtime dependencies in production (all devDependencies only). The main strategic risk is that active compiler development is migrating to microsoft/TypeScript-go (a Go rewrite), so this Node.js repo may receive diminishing feature investment. The package.json version is currently 6.0.0, indicating a major version transition is in progress.

Active areas of work

The repo is in a maintenance/stabilization mode for v6.0.0 (visible in package.json). Active work is limited per the README to: crash fixes introduced in 5.9 or 6.0 that reproduce in 7.0, security issues, and serious regressions. The .github/workflows/ includes create-cherry-pick-pr.yml, sync-branch.yaml, and new-release-branch.yaml, indicating active release branch management. The primary forward development is happening at microsoft/TypeScript-go.

Get running

git clone https://github.com/microsoft/TypeScript.git cd TypeScript npm install npm run build

Run the compiler on a test file:

node ./built/local/tsc.js --version

Run the test suite:

npx hereby runtests

Daily commands:

Build the compiler from source:

npx hereby local

Run all tests:

npx hereby runtests

Run a specific test suite:

npx hereby runtests --suite compiler

Watch mode build:

npx hereby watch-local

Use the locally built tsc:

node ./built/local/tsc.js yourfile.ts

Map of the codebase

  • src — Root source directory containing all TypeScript compiler source code — every contributor must understand this directory structure before making changes
  • Herebyfile.mjs — Primary build orchestration file defining all build tasks, test tasks, and LKG (last known good) targets that drive the entire development workflow
  • package.json — Defines the public API surface, entry points (lib/typescript.js, lib/typescript.d.ts), scripts, and all dependencies for the TypeScript package
  • scripts/processDiagnosticMessages.mjs — Generates the diagnostic message catalog used throughout the compiler — must be understood before adding any new compiler errors or warnings
  • scripts/dtsBundler.mjs — Bundles the public TypeScript API into a single .d.ts declaration file, critical for understanding how the public API surface is constructed and published
  • scripts/build/projects.mjs — Defines all build project configurations and inter-project dependencies, essential for understanding how the compiler, services, and tests are compiled together
  • AGENTS.md — Mandatory reading for all contributors (human and AI) defining coding conventions, prohibited patterns, and repository-specific rules the team enforces

How to make changes

Add a new compiler diagnostic error

  1. Add the new diagnostic message entry with a unique numeric code and category (Error/Warning/Message/Suggestion) to the diagnosticMessages JSON file in src/ (src)
  2. Run the processDiagnosticMessages script to regenerate the strongly-typed diagnostics catalog (diagnosticInformationMap.generated.ts) (scripts/processDiagnosticMessages.mjs)
  3. Reference the new diagnostic in the checker or relevant compiler phase by importing from the generated diagnostics map and calling createDiagnosticForNode() (src)
  4. Add baseline test files to capture expected diagnostic output in the tests/baselines/reference directory and run the test suite to accept new baselines (scripts/build/tests.mjs)

Add a new compiler option (flag)

  1. Add the option definition (name, type, default, description diagnostic) to the commandLineOptions array in src/compiler/commandLineParser.ts (src)
  2. Add the option property to the CompilerOptions interface in src/compiler/types.ts so it is part of the public API (src)
  3. Implement the option's effect in the appropriate compiler phase (checker.ts for type-level, emitter.ts for emit-level) (src)
  4. Update the dtsBundler to ensure the new option type is included in the public API bundle (scripts/dtsBundler.mjs)

Add a new custom ESLint rule for compiler source

  1. Create a new .cjs rule file in the eslint rules directory following the pattern of existing rules (meta + create pattern) (scripts/eslint/rules/debug-assert.cjs)
  2. Add a corresponding test file in the eslint tests directory using the shared RuleTester harness (scripts/eslint/tests/debug-assert.test.cjs)
  3. Register the new rule in the root ESLint configuration file with the desired severity (eslint.config.mjs)

Add a new build task

  1. Define the new task using the hereby task() API with explicit dependencies on existing tasks in the Herebyfile (Herebyfile.mjs)
  2. If the task compiles TypeScript projects, add the project reference configuration to the build projects registry (scripts/build/projects.mjs)
  3. Add any shared utilities needed by the task to the build utils module (scripts/build/utils.mjs)

Why these technologies

  • TypeScript (self-hosted) — The compiler is written in TypeScript itself (bootstrapped via LKG), demonstrating the language's viability for large-scale systems and enabling contributors to use type safety while building the type system
  • Node.js — Provides cross-platform file system access, process management, and a mature module ecosystem needed for a CLI compiler tool without browser constraints
  • Hereby (build tool) — Lightweight, modern task runner replacing Gulp, chosen for simplicity and direct ESM compatibility with the build scripts
  • dprint (formatter) — Extremely fast Rust-based formatter replacing Prettier for a codebase of this size, providing consistent formatting without the performance overhead
  • ESLint with custom rules — Custom rules enforce TypeScript-compiler-specific patterns (Debug.assert usage, no 'in' operator, argument trivia) that generic linters cannot express

Trade-offs already made

  • Single-file compiler output (typescript.js)

    • Why: Simplifies distribution and consumption — users need only require('typescript') without worrying about internal module structure
    • Consequence: The bundle is very large; internal refactoring cannot change the public API surface without a major version bump
  • Bootstrapping via LKG (last known good) snapshot

    • Why: Allows the compiler to be self-hosting without requiring an external TypeScript installation, ensuring deterministic builds
    • Consequence: LKG must be periodically promoted, and breaking changes to the compiler internals require a working LKG before they can be merged
  • No runtime type checking (type erasure)

    • Why: TypeScript types are compile-time only constructs, keeping the emitted JavaScript clean and zero-overhead at runtime
    • Consequence: Runtime type safety requires additional tools (e.g., zod, io-ts); TypeScript cannot enforce types on data from external sources at runtime
  • Structural (duck) typing over nominal typing

    • Why: Better models JavaScript's dynamic nature and maximizes compatibility with existing JS patterns and libraries
    • Consequence: Can produce surprising assignability results; nominal

Traps & gotchas

  1. Tests are baseline-driven: failing a test often means you need to run hereby baseline-accept to update reference files in tests/baselines/reference/ — diff the output first to verify correctness. 2) The build is bootstrapped (TypeScript compiles itself), so you need the LKG (last-known-good) compiler in lib/ which ships in the repo. 3) Node.js >=14.17 is required; mismatched versions cause subtle build failures. 4) npx hereby not npm run — tasks are defined in Herebyfile.mjs, not package.json scripts. 5) New feature PRs are currently being declined per the README — only crash fixes, security issues, and serious regressions are accepted.

Architecture

Concepts to learn

  • Structural type system — TypeScript uses structural (duck) typing rather than nominal typing — understanding this is essential to predicting how checker.ts decides type compatibility
  • Baseline testing — TypeScript's test suite compares compiler output against checked-in reference files (tests/baselines/reference/) rather than assertions — every code change that affects output requires a baseline update
  • Control flow analysis — The checker performs flow-sensitive type narrowing (e.g. type guards, if branches) by building a control flow graph — understanding this explains how typeof x === 'string' narrows types
  • Conditional types and type inference — TypeScript's T extends U ? X : Y system enables higher-kinded type manipulation and is one of the most complex parts of checker.ts, involving deferred resolution and covariance/contravariance checks
  • Language Server Protocol (LSP) — The tsserver binary implements a superset of LSP that editors use for autocomplete, diagnostics, and refactoring — the src/services/ directory implements this layer on top of the compiler
  • Bootstrapped compiler (self-hosting) — TypeScript compiles itself using the LKG (last-known-good) compiler stored in lib/ — changes to the compiler must not break its own compilation, and the build pipeline has specific stages to handle this
  • Declaration emit — Beyond JavaScript emit, tsc generates .d.ts declaration files that encode the public API types of a package — this is a separate emit pipeline in src/compiler/ critical for library authors

Related repos

  • microsoft/TypeScript-go — The active Go rewrite of the TypeScript compiler where all new feature development is happening for TypeScript 7.0+
  • microsoft/vscode — Primary consumer of the TypeScript language service — uses the tsserver binary from this repo for all TypeScript/JavaScript IntelliSense
  • DefinitelyTyped/DefinitelyTyped — Community-maintained type definitions for npm packages that complement the TypeScript compiler's type checking
  • babel/babel — Alternative JavaScript transpiler that added TypeScript syntax stripping (without type checking) as a direct competitor for the emit pipeline
  • nicolo-ribaudo/ts-morph — Higher-level TypeScript compiler API wrapper that many tooling authors use instead of consuming typescript.js directly

PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add twoslash reproduction tests for known edge-case module resolution bugs

The repo already has a .github/workflows/twoslash-repros.yaml workflow and a dedicated issue template at .github/ISSUE_TEMPLATE/module_resolution.yml, indicating module resolution is a frequent pain point. However, twoslash repro tests are a relatively new mechanism in the TypeScript repo and the corpus of covered edge cases is likely thin. Adding twoslash-style repro tests for documented module resolution quirks (e.g. --moduleResolution bundler with dual CJS/ESM packages, exports field priority ordering, or --nodenext with .js extensions) would both exercise the workflow machinery and prevent regressions for issues that appear repeatedly in the tracker.

  • [ ] Browse open/closed GitHub issues tagged with 'Module Resolution' to find 3–5 reproducible bugs that lack a corresponding test in tests/cases/.
  • [ ] For each chosen issue, create a minimal twoslash repro file under the directory consumed by .github/workflows/twoslash-repros.yaml (inspect that workflow file to find the exact target directory, e.g. tests/twoslash/).
  • [ ] Run hereby runtests --testPathPattern=twoslash (or the equivalent target shown in Herebyfile.mjs) locally to confirm the new repros are picked up and produce the expected diagnostics.
  • [ ] Submit a PR that includes the new repro files plus a short comment in each file linking back to the originating GitHub issue number, so future contributors can trace intent.

Split scripts/build/projects.mjs into per-concern modules to reduce file complexity

The scripts/build/ directory contains several focused helpers (options.mjs, utils.mjs, localization.mjs, tests.mjs) but projects.mjs is the central orchestrator and historically grows unbounded as new build targets are added. Refactoring it by extracting logical groupings (e.g. projects.compiler.mjs, projects.services.mjs, projects.lkg.mjs) mirrors the pattern already established by the sibling files, makes onboarding easier, and reduces merge-conflict surface area when multiple contributors add build targets simultaneously.

  • [ ] Open scripts/build/projects.mjs and identify logical groupings of exported task/project definitions (compiler core, language services, LKG/dist targets, test infrastructure).
  • [ ] Create new files such as scripts/build/projects.compiler.mjs and scripts/build/projects.services.mjs, moving the relevant exported constants and functions into each, following the code style of scripts/build/utils.mjs.
  • [ ] Update scripts/build/projects.mjs to re-export everything from the new sub-modules so that Herebyfile.mjs and any other consumers require zero changes.
  • [ ] Run node .gulp.js (or hereby build) and hereby runtests to confirm the build and test suite still pass end-to-end.
  • [ ] Update CONTRIBUTING.md with a brief note explaining the new build-script layout so future contributors know where to add new targets.

Add a dedicated CI workflow to enforce knip.jsonc unused-exports policy on every PR

The repo ships a knip.jsonc configuration file, which means it uses the knip dead-code/unused-export linter, but scanning the .github/workflows/ listing reveals no workflow that actually runs knip on pull requests. Without a CI gate, knip.jsonc rules are only useful if contributors remember to run the tool locally, meaning dead exports accumulate undetected. Adding a lightweight GitHub Actions workflow that runs knip on every PR (and on pushes to main) closes this gap and keeps the public API surface intentional.

  • [ ] Create .github/workflows/knip.yml modelled after the structure of .github/workflows/ci.yml, triggering on `pull

Good first issues

  1. Add missing test coverage for edge cases in src/compiler/checker.ts conditional type resolution — look for untested paths by running c8 coverage with hereby runtests --coverage and examining uncovered branches. 2) Improve JSDoc comments on public API types in lib/typescript.d.ts — many exported interfaces lack parameter descriptions that would help downstream consumers. 3) Audit tests/cases/compiler/ for test files that have no corresponding entry in tests/baselines/reference/ and add missing baselines to prevent regression gaps.

Top contributors

Recent commits

  • f350b52 — Redirect Claude Code to read AGENTS.md (#63446) (RyanCavanaugh)
  • af087e5 — docs: improve Math.sign JSDoc grammar and clarity (#63433) (SkyCoderAakash)
  • 55423ab — Update CONTRIBUTING.md with comment automation policy (#63412) (RyanCavanaugh)
  • f1a9288 — Also check package name validity in InstallPackageRequest (#63401) (jakebailey)
  • c7a0ae1 — Harden ATA package name filtering (#63368) (jakebailey)
  • 5f43505 — Require AI disclosure in PR descriptions (#63366) (RyanCavanaugh)
  • 38c3279 — Document charCodeAt edge case behavior in first line (#63344) (bwalter007)
  • 7b8cb3b — Fix redundant leading apostrophe in TS1344 diagnostic message (#63341) (Copilot)
  • 0844c43 — Mark class property initializers as outside of CFA containers (#63310) (Copilot)
  • 71586ad — Bump the github-actions group with 2 updates (#63319) (dependabot[bot])

Security observations

  • Medium · Outdated or Unpinned Dependency Versions with Wildcard Ranges — package.json - devDependencies. Several devDependencies use caret (^) version ranges (e.g., '@types/node': 'latest', 'eslint': '^10.1.0', 'esbuild': '^0.27.4', 'fast-xml-parser': '^5.5.9'), which allow automatic minor/patch updates. The use of 'latest' for @types/node is particularly risky as it may pull in incompatible or potentially compromised versions without explicit review. Supply chain attacks via dependency confusion or malicious package updates remain a real threat. Fix: Pin all dependency versions to exact versions or use a lock file (package-lock.json is present, which helps). Remove 'latest' tags and replace with explicit pinned versions. Regularly audit dependencies using 'npm audit' and tools like Dependabot (already configured via .github/dependabot.yml, which is a positive sign). Consider using a checksum-based integrity verification.
  • Medium · fast-xml-parser Dependency - Known XML Injection/DoS Risk — package.json - devDependencies (fast-xml-parser ^5.5.9). fast-xml-parser (^5.5.9) is included as a devDependency. XML parsers are historically susceptible to XML External Entity (XXE) injection, billion laughs attacks (DoS), and prototype pollution vulnerabilities depending on configuration and version. If this parser is used to process untrusted XML input in build scripts or tooling, it could lead to information disclosure or denial of service. Fix: Ensure fast-xml-parser is only used in build/scripting contexts with trusted input. Verify the version in use does not have known CVEs via 'npm audit'. Configure the parser to disable external entity processing if applicable. Consider whether this dependency is necessary or can be replaced with a safer alternative.
  • Medium · GitHub Actions Workflow Files Using Mutable Action References — .github/workflows/ (multiple workflow YAML files). The repository contains numerous GitHub Actions workflow files under .github/workflows/. If any of these workflows reference third-party actions using mutable tags (e.g., uses: actions/checkout@v3 instead of a pinned SHA commit hash), they are susceptible to supply chain attacks where a compromised action tag could execute arbitrary code in the CI/CD pipeline with repository permissions. Fix: Pin all GitHub Actions to specific commit SHAs rather than mutable version tags (e.g., uses: actions/checkout@<full-sha> instead of @v4). Use tools like 'actionlint' or 'pin-github-action' to audit and pin workflow action references. This is especially important for actions that have write permissions to the repository.
  • Low · CodeQL Configuration Potentially Insufficient — .github/codeql/codeql-configuration.yml. The presence of .github/codeql/codeql-configuration.yml indicates CodeQL scanning is configured, but without visibility into its contents, it may have excluded important query suites or paths. Misconfigured CodeQL scans may miss vulnerabilities in critical code paths within the TypeScript compiler. Fix: Ensure CodeQL is configured to scan all relevant source paths and uses the 'security-and-quality' or 'security-extended' query suites. Verify that no critical source directories are excluded from analysis. Review the configuration periodically as the codebase evolves.
  • Low · Sensitive Credential Exposure Risk in CI/CD Pipeline Scripts — scripts/, azure-pipelines.release.yml, azure-pipelines.release-publish.yml, .github/workflows/. The presence of scripts interacting with Azure DevOps (azure-devops-node-api), GitHub (octokit/rest), and release pipelines (azure-pipelines.release.yml, azure-pipelines.release-publish.yml) suggests API tokens and secrets are used. If these are hardcoded in scripts or configuration files rather than injected as secrets, they could be exposed in repository history or logs. Fix: Ensure all API tokens, credentials, and secrets are stored as encrypted secrets in GitHub Actions or Azure Pipelines secret stores, never hardcoded in source files. Audit git history for any accidentally committed credentials using tools like git-secrets or trufflehog. Rotate any credentials that may have been exposed.
  • Low · ESLint Custom Rules May Have Security Bypass Potential — undefined. The repository includes custom ESLint rules under scripts Fix: undefined

LLM-derived; treat as a starting point, not a security audit.

Where to read next


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

GO · microsoft/TypeScript — RepoPilot Verdict