TypeDoc vs JSDoc vs API Extractor: TypeScript Documentation Generators (2026)
TL;DR
TypeDoc generates beautiful HTML documentation directly from TypeScript types and JSDoc comments — the standard for TypeScript library documentation. JSDoc is the language-agnostic comment standard that both TypeDoc and API Extractor read, plus a standalone doc generator for JavaScript projects. API Extractor (Microsoft) is for library authors — it generates the canonical public API surface (d.ts rollup), detects breaking changes, and produces API reports for review. For documenting a TypeScript package: TypeDoc. For managing a library's public API contract: API Extractor. For JavaScript-only projects: JSDoc standalone.
Key Takeaways
- typedoc: ~3M weekly downloads — TypeScript-native HTML docs, reads types + JSDoc
- jsdoc: ~5M weekly downloads — the comment standard; also a standalone HTML generator
- @microsoft/api-extractor: ~15M weekly downloads — d.ts rollup, API reports, breaking change detection
- TypeDoc and JSDoc solve "generate readable docs from your code"
- API Extractor solves "enforce public API contracts and detect breaking changes"
- API Extractor produces
api-report.mdfiles that review breaking changes in PRs - Most TypeScript library authors use TypeDoc for docs + API Extractor for API management
Download Trends
| Package | Weekly Downloads | HTML Docs | d.ts Rollup | API Reports | Breaking Change Detection |
|---|---|---|---|---|---|
typedoc | ~3M | ✅ | ❌ | ❌ | ❌ |
jsdoc | ~5M | ✅ | ❌ | ❌ | ❌ |
@microsoft/api-extractor | ~15M | ❌ | ✅ | ✅ | ✅ |
TypeDoc
TypeDoc — the standard for TypeScript HTML documentation:
Setup
npm install -D typedoc
// typedoc.json
{
"entryPoints": ["src/index.ts"],
"out": "docs",
"plugin": [],
"name": "PkgPulse SDK",
"readme": "README.md",
"excludePrivate": true,
"excludeProtected": false,
"excludeInternal": true,
"includeVersion": true,
"theme": "default"
}
// package.json
{
"scripts": {
"docs": "typedoc",
"docs:watch": "typedoc --watch"
}
}
JSDoc comments (TypeDoc reads these)
/**
* Calculate the health score for an npm package based on various metrics.
*
* The health score considers download trends, maintenance activity,
* dependency count, and TypeScript support.
*
* @param packageName - The npm package name (e.g., "react")
* @param options - Optional configuration for the calculation
* @param options.weights - Custom weights for each metric (must sum to 1.0)
* @param options.includeDeprecated - Include deprecated packages in comparison
* @returns A promise resolving to the health score (0-100) and detailed breakdown
*
* @example
* ```typescript
* const health = await getPackageHealth("react")
* console.log(health.score) // 95
* console.log(health.breakdown) // { downloads: 98, maintenance: 92, ... }
* ```
*
* @throws {PackageNotFoundError} If the package doesn't exist in npm registry
* @throws {RateLimitError} If the npm API rate limit is exceeded
*
* @see {@link https://www.pkgpulse.com/docs/health-score} Health Score Documentation
* @since 2.0.0
*/
export async function getPackageHealth(
packageName: string,
options?: HealthScoreOptions
): Promise<PackageHealth> {
// Implementation
}
TypeDoc annotations
/**
* Configuration for the PkgPulse SDK client.
*
* @remarks
* The `apiKey` is required. Get yours at {@link https://www.pkgpulse.com/api-keys}.
*
* @example
* ```typescript
* const client = new PkgPulseClient({
* apiKey: process.env.PKGPULSE_API_KEY!,
* baseUrl: "https://api.pkgpulse.com",
* timeout: 5000,
* })
* ```
*/
export interface PkgPulseConfig {
/** API key from pkgpulse.com/api-keys */
apiKey: string
/**
* Base URL for the API.
* @defaultValue "https://api.pkgpulse.com"
*/
baseUrl?: string
/**
* Request timeout in milliseconds.
* @defaultValue 10000
*/
timeout?: number
/**
* @internal
* Not part of the public API — used for testing.
*/
_mockMode?: boolean
}
/**
* Supported alert types for package monitoring.
* @enum
*/
export type AlertType =
/** Triggered when weekly downloads drop by more than the threshold percentage */
| "downloads_drop"
/** Triggered when a new version is published */
| "version_update"
/** Triggered when a security vulnerability is reported */
| "security"
Deploy to GitHub Pages
# .github/workflows/docs.yml
name: Deploy Docs
on:
push:
branches: [main]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run docs
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
JSDoc
JSDoc — the universal documentation comment standard:
JSDoc as a comment standard (used by everyone)
/**
* Fetches package download statistics from the npm registry.
*
* @param {string} packageName - npm package name
* @param {"last-week"|"last-month"|"last-year"} period - Time period
* @returns {Promise<{downloads: number, start: string, end: string, package: string}>}
* @throws {Error} If the package doesn't exist
*
* @example
* const stats = await getDownloadStats("react", "last-week")
* console.log(stats.downloads) // 45000000
*/
async function getDownloadStats(packageName, period = "last-week") {
const res = await fetch(
`https://api.npmjs.org/downloads/point/${period}/${packageName}`
)
if (!res.ok) throw new Error(`Package ${packageName} not found`)
return res.json()
}
JSDoc with TypeScript (type checking from comments)
// @ts-check — enables TypeScript checking in JavaScript files
/**
* @typedef {Object} PackageHealth
* @property {string} name - Package name
* @property {number} score - Health score 0-100
* @property {boolean} deprecated - Whether the package is deprecated
* @property {string[]} tags - Associated tags
*/
/**
* @param {string} name
* @returns {Promise<PackageHealth>}
*/
async function getHealth(name) {
// TypeScript will type-check this based on the @returns annotation
}
JSDoc standalone generator
// jsdoc.json (config file for jsdoc HTML generator)
{
"source": {
"include": ["src/"],
"includePattern": ".+\\.js(doc)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"plugins": ["plugins/markdown"],
"templates": {
"cleverLinks": false,
"monospaceLinks": false
},
"opts": {
"destination": "./docs/",
"recurse": true,
"readme": "README.md"
}
}
API Extractor
@microsoft/api-extractor — for TypeScript library authors:
Setup
npm install -D @microsoft/api-extractor
npx api-extractor init # Creates api-extractor.json
// api-extractor.json
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "<projectFolder>/dist/index.d.ts",
"apiReport": {
"enabled": true,
"reportFolder": "<projectFolder>/etc/" // Store in git — review changes in PRs
},
"docModel": {
"enabled": true,
"apiJsonFilePath": "<projectFolder>/temp/<unscopedPackageName>.api.json"
},
"dtsRollup": {
"enabled": true,
"untrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-untrimmed.d.ts",
"publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>.d.ts"
},
"tsdocMetadata": { "enabled": true }
}
What API Extractor generates
// API Report (etc/pkgpulse-sdk.api.md) — committed to git:
// This file is checked to detect breaking changes in PRs.
// After running api-extractor run:
/* etc/pkgpulse-sdk.api.md */
// @public
export function getPackageHealth(packageName: string, options?: HealthScoreOptions): Promise<PackageHealth>;
// @public
export interface PackageHealth {
breakdown: HealthBreakdown;
name: string;
score: number;
}
// @internal (not included in public .d.ts rollup)
export function _internalHelper(): void;
Breaking change detection in CI
# .github/workflows/api-review.yml
- name: Run API Extractor
run: npx api-extractor run --local --verbose
# If the public API changed (api-report.md would differ from committed version):
# → API Extractor exits with error code
# → PR fails until the api-report.md is updated and committed
# → Forces explicit review of all breaking changes
API annotations
/**
* @public — included in public .d.ts
*/
export function getPackageHealth(name: string): Promise<PackageHealth> { ... }
/**
* @beta — public but not stable
*/
export function getExperimentalMetrics(name: string): Promise<unknown> { ... }
/**
* @alpha — very early, may change frequently
*/
export function _dangerousLowLevelAccess(): void { ... }
/**
* @internal — stripped from public .d.ts rollup
*/
export function _privateHelper(): void { ... }
/**
* @deprecated Use getPackageHealth() instead.
*/
export function getHealth(name: string): Promise<PackageHealth> { ... }
Feature Comparison
| Feature | TypeDoc | JSDoc (standalone) | API Extractor |
|---|---|---|---|
| HTML documentation | ✅ Beautiful | ✅ Basic | ❌ |
| TypeScript-native | ✅ | ❌ (comment-based) | ✅ |
| d.ts rollup | ❌ | ❌ | ✅ |
| Breaking change detection | ❌ | ❌ | ✅ |
| API reports | ❌ | ❌ | ✅ |
| Plugins | ✅ Rich | ✅ | ❌ |
| @alpha/@beta/@internal | ✅ | ❌ | ✅ |
| Markdown integration | ✅ | ✅ | ✅ |
| CI integration | ✅ | ✅ | ✅ |
When to Use Each
Choose TypeDoc if:
- Publishing a TypeScript library on npm and want HTML docs
- You want docs generated from your TypeScript types directly
- Deploying documentation to GitHub Pages or a docs site
- The standard choice for TypeScript library documentation
Choose JSDoc (comments) everywhere:
- JSDoc comments are read by TypeDoc, API Extractor, VS Code IntelliSense, and TypeScript
- Even if you never run jsdoc standalone, add JSDoc comments to all exported functions
- Use JSDoc standalone for pure JavaScript libraries (not TypeScript)
Choose API Extractor if:
- Publishing a TypeScript library with a stable public API
- You want to detect breaking changes in PRs before they ship
- Your library has multiple consumers who rely on API stability
- You need a clean d.ts rollup (single file instead of many)
- Working at an organization with formal API review processes
Common pattern for npm library authors:
TypeDoc → HTML docs hosted on GitHub Pages
API Extractor → d.ts rollup + API report in git (for breaking change detection)
Both together → comprehensive library publishing setup
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on typedoc v0.26.x, jsdoc v4.x, and @microsoft/api-extractor v7.x.
Compare documentation and developer tool packages on PkgPulse →