microsoft/TypeScript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
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
[](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 changesHerebyfile.mjs— Primary build orchestration file defining all build tasks, test tasks, and LKG (last known good) targets that drive the entire development workflowpackage.json— Defines the public API surface, entry points (lib/typescript.js, lib/typescript.d.ts), scripts, and all dependencies for the TypeScript packagescripts/processDiagnosticMessages.mjs— Generates the diagnostic message catalog used throughout the compiler — must be understood before adding any new compiler errors or warningsscripts/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 publishedscripts/build/projects.mjs— Defines all build project configurations and inter-project dependencies, essential for understanding how the compiler, services, and tests are compiled togetherAGENTS.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
- 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) - Run the processDiagnosticMessages script to regenerate the strongly-typed diagnostics catalog (diagnosticInformationMap.generated.ts) (
scripts/processDiagnosticMessages.mjs) - Reference the new diagnostic in the checker or relevant compiler phase by importing from the generated diagnostics map and calling createDiagnosticForNode() (
src) - 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)
- Add the option definition (name, type, default, description diagnostic) to the commandLineOptions array in src/compiler/commandLineParser.ts (
src) - Add the option property to the CompilerOptions interface in src/compiler/types.ts so it is part of the public API (
src) - Implement the option's effect in the appropriate compiler phase (checker.ts for type-level, emitter.ts for emit-level) (
src) - 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
- 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) - Add a corresponding test file in the eslint tests directory using the shared RuleTester harness (
scripts/eslint/tests/debug-assert.test.cjs) - Register the new rule in the root ESLint configuration file with the desired severity (
eslint.config.mjs)
Add a new build task
- Define the new task using the hereby task() API with explicit dependencies on existing tasks in the Herebyfile (
Herebyfile.mjs) - If the task compiles TypeScript projects, add the project reference configuration to the build projects registry (
scripts/build/projects.mjs) - 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
- Tests are baseline-driven: failing a test often means you need to run
hereby baseline-acceptto update reference files intests/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 inlib/which ships in the repo. 3) Node.js >=14.17 is required; mismatched versions cause subtle build failures. 4)npx herebynotnpm run— tasks are defined inHerebyfile.mjs, notpackage.jsonscripts. 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.tsdecides 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,
ifbranches) by building a control flow graph — understanding this explains howtypeof x === 'string'narrows types - Conditional types and type inference — TypeScript's
T extends U ? X : Ysystem enables higher-kinded type manipulation and is one of the most complex parts ofchecker.ts, involving deferred resolution and covariance/contravariance checks - Language Server Protocol (LSP) — The
tsserverbinary implements a superset of LSP that editors use for autocomplete, diagnostics, and refactoring — thesrc/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,
tscgenerates.d.tsdeclaration files that encode the public API types of a package — this is a separate emit pipeline insrc/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 IntelliSenseDefinitelyTyped/DefinitelyTyped— Community-maintained type definitions for npm packages that complement the TypeScript compiler's type checkingbabel/babel— Alternative JavaScript transpiler that added TypeScript syntax stripping (without type checking) as a direct competitor for the emit pipelinenicolo-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 inHerebyfile.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.mjsand 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.mjsandscripts/build/projects.services.mjs, moving the relevant exported constants and functions into each, following the code style ofscripts/build/utils.mjs. - [ ] Update
scripts/build/projects.mjsto re-export everything from the new sub-modules so thatHerebyfile.mjsand any other consumers require zero changes. - [ ] Run
node .gulp.js(orhereby build) andhereby runteststo confirm the build and test suite still pass end-to-end. - [ ] Update
CONTRIBUTING.mdwith 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.ymlmodelled after the structure of.github/workflows/ci.yml, triggering on `pull
Good first issues
- Add missing test coverage for edge cases in
src/compiler/checker.tsconditional type resolution — look for untested paths by running c8 coverage withhereby runtests --coverageand examining uncovered branches. 2) Improve JSDoc comments on public API types inlib/typescript.d.ts— many exported interfaces lack parameter descriptions that would help downstream consumers. 3) Audittests/cases/compiler/for test files that have no corresponding entry intests/baselines/reference/and add missing baselines to prevent regression gaps.
Top contributors
- @jakebailey — 32 commits
- @dependabot[bot] — 10 commits
- @DanielRosenwasser — 10 commits
- @RyanCavanaugh — 9 commits
- @Copilot — 8 commits
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
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.