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.
- 🎯 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
- 🧩 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
- 📛 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
- 🛠️ 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
npm install @qlik/dts-bundler
# or
pnpm add @qlik/dts-bundler
# or
yarn add @qlik/dts-bundlerimport { 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);bundle-types -e < entry > -o < output > [-i < inlinedLibraries > ]-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
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-typesWhen 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);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-cCreate 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);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();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
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;
}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 {};For complete API documentation, see the API Reference.
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);| 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.
-
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
- 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
- Node.js >= 20
- TypeScript ^5.9.3 (included as a dependency)
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
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)
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
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:updateTests 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
Contributions are welcome! Please feel free to submit a Pull Request.
- API Reference — Complete API documentation
- TypeScript Handbook: Declaration Files
ISC