@microsoft/api-extractor, dts-generator, tsd, and typedoc address different stages of the TypeScript library lifecycle. @microsoft/api-extractor is an enterprise-grade tool for rolling up .d.ts files, validating API surfaces, and generating strict documentation. dts-generator is a legacy utility for concatenating declaration files, largely superseded by native TypeScript features. tsd is a testing framework specifically for asserting the types of .d.ts files, not for generating them. typedoc is a documentation generator that converts TypeScript source comments into static HTML sites, similar to JSDoc but with type awareness.
When building and maintaining TypeScript libraries, developers often face a confusing array of tools for handling declaration files (.d.ts) and documentation. While the TypeScript compiler (tsc) handles the basics, professional workflows often require specialized tools to bundle declarations, test type safety, or generate rich documentation. Let's break down @microsoft/api-extractor, dts-generator, tsd, and typedoc to see where each fits in a modern architecture.
One of the most common pain points in library development is managing multiple internal .d.ts files. Consumers usually prefer a single entry point. This is where @microsoft/api-extractor and the legacy dts-generator differ significantly.
@microsoft/api-extractor analyzes your compiled output and rolls up all declarations into a single .d.ts file. It also trims unused exports based on your configuration, ensuring a clean public API.
// api-extractor.json configuration
{
"mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
"bundledPackages": [],
"compiler": {
"tsconfigFilePath": "<projectFolder>/tsconfig.json"
},
"apiReport": {
"enabled": true
},
"dtsRollup": {
"enabled": true,
"untrimmedFilePath": "<projectFolder>/dist/my-lib.d.ts"
}
}
dts-generator was an early solution that simply concatenated files in a specific order. It lacks the semantic understanding of the code that api-extractor has and does not handle trimming or API validation.
# dts-generator: CLI usage (Legacy)
# Concatenates all .d.ts files from src into dist/index.d.ts
dts-generator --out dist/index.d.ts --name my-lib --src src/**/*.d.ts
tsd does not bundle files. It focuses purely on testing the resulting types.
// tsd: No bundling capability
// This tool is used in a test file to assert types, not to create output files
import { expectType } from 'tsd';
// ... assertions here
typedoc also does not bundle declaration files for distribution. It reads them to generate documentation but leaves the build artifacts untouched.
# typedoc: Generates HTML, not .d.ts bundles
typedoc --out docs ./src/index.ts
While other tools focus on building or documenting, tsd fills a critical gap: verifying that your types actually work as intended for the end user.
tsd allows you to write tests that assert types without running any JavaScript. If the types change in a breaking way, the test fails.
// __tests__/index.test-d.ts
import { expectType, expectError } from 'tsd';
import { MyFunction } from '../dist';
// Asserts that MyFunction returns a string
expectType<string>(MyFunction('input'));
// Asserts that passing a number causes a type error
expectError(MyFunction(123));
@microsoft/api-extractor performs a different kind of validation. It checks your API surface against a stored "signature" file to ensure you haven't accidentally changed public contracts.
# api-extractor: Validates API surface against a baseline
npx api-extractor run --local
# If you changed a public method signature, this command fails
# and prompts you to update the .api.md report file.
dts-generator has no testing capabilities. It is purely a file manipulation tool.
# dts-generator: No test command exists
# Usage is limited to file generation only
typedoc does not test types. However, if your types are invalid, TypeDoc may fail to parse the source files, acting as a passive sanity check.
# typedoc: Fails if source has syntax errors, but doesn't assert logic
typedoc --skipErrorChecking false ./src
Documentation needs vary by project. Some teams need a full website; others need a strict changelog of API changes.
typedoc excels at creating beautiful, navigable HTML documentation sites from JSDoc comments and TypeScript types.
# typedoc: Generate a full HTML site
typedoc --out ./docs --entryPointStrategy expand ./src
// Result: A folder of HTML files with search, hierarchy, and code highlighting
@microsoft/api-extractor generates a Markdown API report (.api.md). This isn't a website for users, but a precise contract for maintainers to review changes.
// Output: temp/my-lib.api.md (Generated by api-extractor)
## Functions
### myFunction
> Signature: `myFunction(input: string): string`
>
> Remarks:
> Performs a specific operation on the input string.
dts-generator does not generate documentation. It only produces a combined .d.ts file which serves as raw data for IDEs, not human-readable docs.
// dts-generator output: A raw .d.ts file
// Not suitable for direct human reading as documentation
declare module 'my-lib' {
export function myFunction(input: string): string;
}
tsd does not generate documentation. Its output is strictly pass/fail test results in the terminal.
# tsd output: Terminal test results
# β index.test-d.ts
# β index.test-d.ts (if types mismatch)
It is crucial to note that dts-generator is effectively deprecated for modern workflows. Before TypeScript 2.0, developers needed external tools to combine declaration files. Today, the TypeScript compiler supports declarationMap and modern bundlers (like Rollup or Vite) can handle .d.ts files natively. More importantly, @microsoft/api-extractor provides a superior, semantically aware alternative for rolling up types.
// Modern Alternative: Using TypeScript native features + api-extractor
// tsconfig.json
{
"compilerOptions": {
"declaration": true,
"declarationMap": true // Native source mapping for .d.ts
}
}
// Then use api-extractor for the final rollup, avoiding dts-generator entirely.
Using dts-generator in a new project introduces technical debt and removes the safety checks provided by newer tools.
You are building a component library and want to ensure consumers get a single type definition file and that you don't break APIs accidentally.
@microsoft/api-extractor.api.md report.// package.json script
"scripts": {
"build": "tsc && api-extractor run --local"
}
You maintain a low-level utility package and need to guarantee that your types support both string and number inputs without writing runtime tests.
tsd// __tests__/utils.test-d.ts
import { expectType } from 'tsd';
expectType<number | string>(myUtil(1));
expectType<number | string>(myUtil('a'));
Your team needs a searchable website to understand how to use the internal design system.
typedoc# Command to generate docs for the team wiki
typedoc --out ./wiki-src --theme default ./src/components
You are maintaining an old library that uses dts-generator to merge files.
@microsoft/api-extractordts-generator is obsolete. Moving to api-extractor improves reliability and adds API validation.// Migration step: Replace dts-generator call in build script
// OLD: dts-generator --out dist/index.d.ts ...
// NEW: api-extractor run
| Feature | @microsoft/api-extractor | dts-generator | tsd | typedoc |
|---|---|---|---|---|
| Primary Goal | Bundle & Validate API | Concatenate Files (Legacy) | Test Types | Generate HTML Docs |
| Output Format | .d.ts bundle, .api.md | .d.ts bundle | CLI Pass/Fail | HTML Website |
| API Validation | β Strict contract checking | β None | β οΈ Type structure only | β None |
| Status | π’ Active / Industry Standard | π΄ Deprecated / Legacy | π’ Active | π’ Active |
| Best For | Library Publishers | None (Migrate away) | Type Test Authors | Doc Site Maintainers |
For professional TypeScript development, your toolkit should look like this:
@microsoft/api-extractor for your build pipeline. It is the only robust solution for bundling declarations and enforcing API stability in published packages.tsd in your test suite. It ensures your types remain correct and backward-compatible without bloating your runtime code.typedoc if you need a public-facing documentation website. It complements api-extractor by providing the human-readable layer on top of your strict API definitions.dts-generator. It solves a problem that modern TypeScript and api-extractor have already solved better. Removing it simplifies your dependency tree and reduces risk.By combining these tools, you create a workflow that not only builds code but also guarantees the quality and usability of your types for every consumer.
Choose this if you are publishing a professional TypeScript library to npm and need to bundle multiple .d.ts files into a single entry point, enforce API stability rules, and generate strict API reports. It is the industry standard for library authors who need control over their public surface area and want to prevent accidental breaking changes.
Avoid this package for new projects. It was designed to concatenate declaration files before TypeScript 2.0 introduced native declarationMap and bundling capabilities. Using it today adds unnecessary complexity and maintenance overhead when the TypeScript compiler (tsc) or api-extractor can handle these tasks more reliably.
Choose tsd if you need to write unit tests specifically for your TypeScript definition files (.d.ts). It is essential for library authors who want to verify that their types work correctly for consumers without writing implementation code. Do not use it for generating documentation or bundling declarations.
Choose typedoc if your primary goal is to generate a browsable HTML documentation website from your TypeScript source code and JSDoc comments. It is ideal for creating public-facing docs for internal tools or open-source libraries, but it does not bundle .d.ts files or enforce API contracts like api-extractor does.
Β Β Β Β Β https://api-extractor.com/
API Extractor helps you build better TypeScript library packages. Suppose for example that your company has published an NPM package called "awesome-widgets" that exports many classes and interfaces. As developers start to depend on your library, you may encounter issues such as...
Accidental breaks: People keep reporting that their code won't compile after a supposedly "minor" update. To address this, you boldly propose that every awesome-widgets pull request must be approved by an experienced developer from your team. But that proves unrealistic -- nobody has time to look at every single PR! What you really need is a way to detect PRs that change API contracts, and flag them for review. That would focus attention in the right place... but how to do that?
Missing exports: Suppose the awesome-widgets package exports an API function AwesomeButton.draw() that requires a parameter of type DrawStyle, but you forgot to export this enum. Things seem fine at first, but when a developer tries to call that function, they discover that there's no way to specify the DrawStyle. How to avoid these oversights?
Accidental exports: You meant for your DrawHelper class to be kept internal, but one day you realize it's being exported. When you try to remove it, consumers complain that they're using it. How do we avoid this in the future?
Alpha/Beta graduation: You want to release previews of new APIs that are not ready for prime time yet. But if you did a major SemVer bump every time these definitions evolve, the villagers would be after you with torches and pitchforks! A better approach is to designate certain classes/members as alpha quality, then promote them to beta and finally to public as they mature. But how to indicate this to your consumers? (And how to detect scoping mistakes? A public function should never return a beta result.)
*.d.ts rollup: You webpacked your library into a nice *.js bundle file -- so why ship your typings as a messy tree of lib/*.d.ts files full of private definitions? Can't we consolidate them into a tidy *.d.ts rollup file? And if you publish internal/beta/public releases, each release type should get its own *.d.ts file with appropriate trimming. Developers building a production project don't want to see a bunch of internal and beta members in their VS Code IntelliSense!
Online documentation: You have faithfully annotated each TypeScript member with nice TSDoc descriptions. Now that your library has shipped, it's time to set up a nicely formatted API reference. What tool to use?
API Extractor provides an integrated, professional-quality solution for all these problems. It is invoked at build time by your toolchain and leverages the TypeScript compiler engine to:
Best of all, API Extractor is free and open source. Join the community and create a pull request!
For more details and support resources, please visit: https://api-extractor.com/
API Extractor is part of the Rush Stack family of projects.