@qlik/dts-bundler
v1.1.0
Published
Bundle TypeScript declaration files into a single file
Readme
TypeScript Declaration Bundler
A tool for bundling TypeScript files (.ts and/or .d.ts) by inlining local imports and optionally inlining types from specified npm packages. Works both as a CLI tool and as a library you can import in your Node.js projects.
Features
Core Bundling
- 🎯 Inline local imports — Automatically resolves and inlines all relative imports (
./or../) - 📦 Selective library inlining — Optionally inline types from specific npm packages
- 🔄 External import consolidation — Keeps external imports at the top of the bundled file
- 🎨 Type-only import handling — Properly handles
import typestatements - 🔁 Export re-export resolution — Resolves
export * fromstatements
Advanced Capabilities
- 🧩 Ambient module inlining — Optionally inline
declare module "..."blocks for external modules - 🌐
declare globalsupport — Control whetherdeclare globalblocks are inlined or preserved - 🔀 Declaration merging — Correctly handles TypeScript declaration merging scenarios
- 🌳 Tree shaking — Removes unused declarations from the output
- 🏷️ Name collision resolution — Automatically resolves naming conflicts across files
Output Control
- 📛 UMD module name — Generate UMD-compatible output with
export as namespace - 🔤 Sorted output — Optionally sort declarations alphabetically for consistent diffs
- 📜 Banner control — Include or exclude the generated banner comment
- 🔒 Preserve const enums — Respect
preserveConstEnumscompiler option - 📚 Triple-slash references — Automatically add
/// <reference types="..." />for@types/*packages
Developer Experience
- 🛠️ Dual usage — Use as CLI tool or import as a library
- ✨ Full TypeScript support — Complete type definitions included
- ⚡ Fast — Built on the TypeScript compiler API for accurate and efficient parsing
Installation
npm install @qlik/dts-bundler
# or
pnpm add @qlik/dts-bundler
# or
yarn add @qlik/dts-bundlerUsage
As a Library
import { bundleTypes } from "@qlik/dts-bundler";
import fs from "fs";
// Basic usage - returns bundled content as string
const bundledContent = bundleTypes({
entry: "./src/types.ts",
});
// Write to file
fs.writeFileSync("./dist/bundle.d.ts", bundledContent);
// With inlined libraries
const bundledWithLibs = bundleTypes({
entry: "./src/types.ts",
inlinedLibraries: ["@my-org/types", "some-package"],
inlineDeclareExternals: true,
});
fs.writeFileSync("./dist/bundle.d.ts", bundledWithLibs);As a CLI Tool
bundle-types -e < entry > -o < output > [-i < inlinedLibraries > ]CLI Options
-e, --entry <file>- Required: Entry TypeScript file to bundle-o, --output <file>- Required: Output file path for bundled types-i, --inlinedLibraries <list>- Optional: Comma-separated list of npm packages to inline-h, --help- Show help message
CLI Examples
Basic usage (inline only local imports):
bundle-types -e ./src/types.ts -o ./dist/bundle.d.tsWith npm package inlining:
bundle-types \
-e ./src/types.ts \
-o ./dist/bundle.d.ts \
-i @my-org/types-pkg,@another/types-pkgUsing npm scripts (add to package.json):
{
"scripts": {
"bundle-types": "bundle-types -e ./src/types.ts -o ./dist/bundle.d.ts"
}
}Then run:
npm run bundle-typesReal-World Use Cases
Use Case 1: Publishing a Library
When publishing a library, bundle internal types but keep framework types external:
import { bundleTypes } from "@qlik/dts-bundler";
import fs from "fs";
const bundled = bundleTypes({
entry: "./src/index.ts",
inlinedLibraries: ["@my-company/internal-types"],
});
fs.writeFileSync("./dist/index.d.ts", bundled);Use Case 2: Monorepo Type Sharing
In a monorepo, inline types from your own packages:
bundle-types \
-e ./src/types.ts \
-o ./dist/types.d.ts \
-i @myorg/pkg-a,@myorg/pkg-b,@myorg/pkg-cUse Case 3: Single File Distribution
Create a single file with all types for easy distribution:
import { bundleTypes } from "@qlik/dts-bundler";
import fs from "fs";
const bundled = bundleTypes({
entry: "./src/api.types.ts",
});
fs.writeFileSync("./api-complete.d.ts", bundled);Use Case 4: Build Pipeline Integration
Integrate into your build process:
// build.js
import { bundleTypes } from "@qlik/dts-bundler";
import fs from "fs";
async function build() {
// ... other build steps
const bundled = bundleTypes({
entry: "./src/public-api.ts",
});
fs.writeFileSync("./dist/index.d.ts", bundled);
console.log("✓ Types bundled!");
}
build();How It Works
The bundler performs the following steps:
- Parse Entry File: Reads and parses the entry TypeScript file using the TypeScript compiler API
- Resolve Imports:
- Local imports (starting with
./or../) are always resolved and inlined - Imports from packages in the
inlinedLibrarieslist are also inlined - All other imports are tracked as external dependencies
- Local imports (starting with
- Recursive Processing: Recursively processes all files that should be inlined
- Generate Output:
- External imports are consolidated and placed at the top
- All inlined type declarations follow
- An
export {}statement ensures the file is treated as a module
Example Transformation
Input Files
src/types.ts:
import type { ExternalType } from "@external/package";
import type { LocalType } from "./local-types";
export interface MyType extends LocalType {
external: ExternalType;
}src/local-types.ts:
export interface LocalType {
id: string;
name: string;
}Output File
dist/bundle.d.ts:
// Generated by @qlik/dts-bundler
import type { ExternalType } from "@external/package";
export interface LocalType {
id: string;
name: string;
}
export interface MyType extends LocalType {
external: ExternalType;
}
export {};API Reference
For complete API documentation, see the API Reference.
Quick Reference
bundleTypes(options)
Bundle TypeScript declaration files.
import { bundleTypes } from "@qlik/dts-bundler";
import fs from "fs";
const bundled = bundleTypes({
entry: "./src/types.ts",
inlinedLibraries: ["@my-org/types"],
inlineDeclareExternals: true,
});
fs.writeFileSync("./dist/bundle.d.ts", bundled);Options Summary
| Option | Type | Default | Description |
| -------------------------- | ---------- | ----------- | ----------------------------------------------- |
| entry | string | — | (Required) Entry TypeScript file path |
| inlinedLibraries | string[] | [] | Libraries to inline into the bundle |
| allowedTypesLibraries | string[] | undefined | @types/* packages for triple-slash references |
| importedLibraries | string[] | undefined | Libraries to keep as imports |
| inlineDeclareGlobals | boolean | false | Inline declare global blocks |
| inlineDeclareExternals | boolean | false | Inline declare module blocks |
| exportReferencedTypes | boolean | false | Auto-export referenced types |
| noBanner | boolean | false | Exclude banner comment |
| sortNodes | boolean | false | Sort declarations alphabetically |
| umdModuleName | string | undefined | UMD module name (export as namespace) |
| respectPreserveConstEnum | boolean | false | Respect tsconfig preserveConstEnums |
See the full API documentation for detailed descriptions and examples of each option.
Tips & Best Practices
Multiple libraries: Separate with commas (CLI) or use an array (library)
# CLI -i @org/pkg1,@org/pkg2,@org/pkg3// Library inlinedLibraries: ["@org/pkg1", "@org/pkg2", "@org/pkg3"];Scoped packages: Include the full scope
inlinedLibraries: ["@mycompany/types", "@anothercompany/utils"];Package subpaths: Specify the exact import path
inlinedLibraries: ["@mycompany/types/dist/api"];Check the output: Always verify the generated file matches your expectations
bundle-types -e ./src/types.ts -o ./dist/bundle.d.ts head -50 ./dist/bundle.d.ts
Limitations
- Only handles TypeScript files (
.ts,.tsx,.mts,.cts,.d.ts,.d.mts,.d.cts) - Does not handle runtime JavaScript code (this is a type bundler)
- Assumes all imported files exist and are accessible
- Does not perform type checking (use
tscfor that) - Circular dependencies may cause issues in complex scenarios
Requirements
- Node.js >= 20
- TypeScript ^5.9.3 (included as a dependency)
Troubleshooting
"Could not resolve import" warning
This warning appears when the bundler cannot find an imported file. Check:
- The file path is correct
- The file has a
.ts,.tsx, or.d.tsextension - The file exists at the resolved location
Duplicate type definitions
If you see duplicate types in the output, ensure:
- You're not importing the same file through multiple paths
- Your import paths are consistent (absolute vs relative)
Process exits unexpectedly
If the entry file doesn't exist, the process will exit with code 1. Ensure:
- The entry file path is correct
- The file exists before running the bundler
Development
Running Tests
The project uses vitest for testing with snapshot testing for output verification.
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Update snapshots when output changes are intentional
pnpm test:updateSnapshot Testing
Tests use snapshots to verify bundler output. If you make changes that affect the generated output:
- Run
pnpm testto see the diff - Review the changes carefully
- If correct, run
pnpm test:updateto update snapshots - Commit the updated snapshot files
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Related
- API Reference — Complete API documentation
- TypeScript Handbook: Declaration Files
License
ISC
