TypeScript Declarations
Bunup automatically generates TypeScript declaration files (.d.ts, .d.mts, or .d.cts) for your library. These files tell other developers (and TypeScript) what types your library exports, enabling proper type checking and autocomplete when others use your code.
Isolated Declarations
Enable isolatedDeclarations in your tsconfig:
{
"compilerOptions": {
"declaration": true,
"isolatedDeclarations": true
}
}TypeScript 5.5's isolated declarations changes how declaration files are generated. Instead of analyzing your entire project to figure out types (slow), it processes each file independently (instant). This requires explicit return types on your public exports only - a good practice that makes your API clearer and more predictable.
This transforms builds from seconds/minutes to milliseconds (50-100x faster), enabling instant builds and rebuilds, creates clearer APIs, and ensures compatibility with modern build tools.
// Required: Explicit return type on public exports
export function getData(): Promise<User> {
return fetchUser();
}
// Internal functions don't need explicit types
function fetchUser() {
return api.get('/user');
}Learn more about isolated declarations here.
For new projects, we strongly recommend isolated declarations for instant builds and rebuilds and clearer APIs. Explicitly typing your public exports is considered a best practice for library development.
You only need to disable isolated declarations in rare cases with complex generic types that are genuinely difficult to type explicitly (like some advanced Zod schemas). Check the Infer Types section for this alternative approach.
Basic
Bunup automatically generates TypeScript declaration files for all TypeScript entry points that require them. Files that do not contain exports, or for which declarations are unnecessary, are skipped.
Declaration Splitting
Declaration splitting prevents code duplication when multiple entry points share the same types. Instead of copying shared types into every declaration file, Bunup extracts them into separate chunk files that get imported where needed.
bunup --dts.splittingexport default defineConfig({
dts: {
splitting: true,
},
});Without splitting:
dist/
├── index.d.ts # ~45KB (includes duplicated types)
└── utils.d.ts # ~40KB (includes duplicated types)With splitting:
dist/
├── index.d.ts # ~15KB, imports shared types
├── utils.d.ts # ~10KB, imports shared types
└── shared/chunk-abc123.d.ts # ~30KB, shared types extracted hereThe result is smaller files with no duplicate type definitions.
Minification
You can minify the generated declaration files to reduce their size:
bunup --dts.minifyexport default defineConfig({
dts: {
minify: true,
},
});Minification keeps your public API names unchanged but shortens internal type names and removes comments. This reduces file size significantly, useful when bundle size matters more than readable type definitions.
Example
Original:
type DeepPartial<T> = { [P in keyof T]? : DeepPartial<T[P]> };
interface Response<T> {
data: T;
error?: string;
meta?: Record<string, unknown>;
}
declare function fetchData<T>(url: string, options?: RequestInit): Promise<Response<T>>;
export { fetchData, Response, DeepPartial };Minified:
type e<T>={[P in keyof T]?:e<T[P]>};interface t<T>{data:T;error?:string;meta?:Record<string,unknown>;}declare function n<T>(url:string,options?:RequestInit): Promise<t<T>>;export{n as fetchData,t as Response,e as DeepPartial};Infer Types
By default, Bunup uses isolated declarations which require explicit type annotations. The inferTypes option switches back to traditional TypeScript compilation, allowing you to rely on TypeScript's automatic type inference instead of writing explicit return types.
This is useful for projects with complex generic types where explicit typing is verbose or challenging.
bunup --dts.infer-typesexport default defineConfig({
dts: {
inferTypes: true,
},
});TIP
For new projects, stick with isolated declarations (default behavior) for instant builds and rebuilds and clearer APIs. Only use inferTypes when explicit typing becomes impractical.
Tsgo
When inferTypes is enabled, Bunup uses the regular TypeScript compiler (tsc) by default. You can switch to TypeScript's experimental native compiler (tsgo) for ~10x faster declaration generation.
First, install the required package:
bun add --dev @typescript/native-previewThen enable tsgo:
bunup --dts.infer-types --dts.tsgoexport default defineConfig({
dts: {
inferTypes: true,
tsgo: true,
},
});INFO
tsgo only works with inferTypes enabled. It's experimental but stable enough for declaration generation. Once TypeScript officially releases it, Bunup will use tsgo by default when inferTypes is enabled.
Custom Entry Points
By default, Bunup generates declarations for all your entry points. You can specify which files should have declarations generated:
# Single entry
bunup src/index.ts src/utils.ts --dts.entry src/index.ts
# Multiple entries
bunup src/index.ts src/utils.ts src/types.ts --dts.entry src/index.ts,src/types.tsexport default defineConfig({
entry: ['src/index.ts', 'src/utils.ts'],
dts: {
// Only generate declarations for index.ts
entry: ['src/index.ts'],
},
});Using Glob Patterns
Bunup supports glob patterns to match multiple files:
# Single glob pattern
bunup --dts.entry "src/public/**/*.ts"
# Multiple patterns (including exclusions)
bunup --dts.entry "src/public/**/*.ts,!src/public/dev/**/*"export default defineConfig({
dts: {
entry: [
'src/public/**/*.ts',
'!src/public/dev/**/*'
]
}
});You can use:
- Simple patterns like
src/**/*.tsto include files - Exclude patterns starting with
!to filter out specific files - Both for main entries and declaration entries
TypeScript Configuration
You can specify a custom tsconfig file for declaration generation. This mainly affects how TypeScript resolves import paths during the declaration generation process.
See Custom Tsconfig Path for details.
By default, the nearest tsconfig.json file will be used.
Resolving External Types
When your code imports types from external packages, you might need to include those type definitions in your declaration files. The resolve option tells Bunup to look up and include external types from your dependencies.
# Enable resolving all external types
bunup --dts.resolveexport default defineConfig({
dts: {
// Enable resolving all external types
resolve: true,
},
});You can also specify which packages to resolve types for:
# Single package
bunup --dts.resolve react
# Multiple packages
bunup --dts.resolve react,lodash,@types/nodeexport default defineConfig({
dts: {
// Only resolve types from these specific packages
resolve: ['react', 'lodash', /^@types\//],
},
});Disabling Declaration Generation
You can completely disable automatic declaration file generation:
bunup --no-dtsexport default defineConfig({
entry: "src/index.ts",
dts: false,
});This is useful when you want to handle declaration generation yourself or when working on projects that don't need type definitions.