Type Generation
Generate TypeScript definitions from your CLI commands for enhanced developer experience
Type Generation
Bunli's code generation system creates TypeScript definitions from your CLI commands, providing compile-time type safety, autocomplete, and enhanced developer experience.
Type generation works alongside Bunli's runtime type inference to provide both compile-time and runtime type safety for your CLI applications.
Quick Start
Type generation is automatically enabled in all Bunli projects. No configuration needed!
import { defineConfig } from '@bunli/core'
export default defineConfig({
name: 'my-cli',
version: '1.0.0',
})Types are generated automatically when you run any Bunli command:
# Types generated automatically
bunli dev
bunli build
# Or generate manually
bunli generateGenerated API Overview
The generator creates a comprehensive TypeScript API from your commands:
GeneratedCLI Interface
interface GeneratedCLI {
register(cli?: CLI<any>): GeneratedCLI
list(): Array<{
name: GeneratedNames
command: Command<any>
metadata: GeneratedCommandMeta
}>
get<Name extends GeneratedNames>(name: Name): Command<any>
getMetadata<Name extends GeneratedNames>(name: Name): GeneratedCommandMeta
getFlags<Name extends GeneratedNames>(name: Name): CommandOptions<Name>
getFlagsMeta<Name extends GeneratedNames>(name: Name): Record<string, GeneratedOptionMeta>
withCLI(cli: CLI<any>): { execute(name: string, options: unknown): Promise<void> }
}Helper Functions
// Get command metadata by name
function getCommandApi<Name extends GeneratedNames>(name: Name): GeneratedCommandMeta
// Get all command names
function getCommandNames(): GeneratedNames[]
// List all commands with metadata
function listCommands(): GeneratedNames[]
// Get typed flags for a command
function getTypedFlags<Name extends GeneratedNames>(name: Name): CommandOptions<Name>
// Validate command arguments
function validateCommand<Name extends GeneratedNames>(name: Name, flags: Record<string, unknown>): ValidationResult
// Find commands by name or description
function findCommandByName<Name extends GeneratedNames>(name: Name): CommandInfo
function findCommandsByDescription(searchTerm: string): CommandInfo[]IDE Integration Features
Autocomplete and IntelliSense
Generated types provide rich IDE support:
import { getCommandApi, getCommandNames } from './.bunli/commands.gen'
// Full autocomplete for command names
const commandNames = getCommandNames() // 'greet' | 'deploy' | 'test' | ...
// Type-safe command access
const greetApi = getCommandApi('greet')
// greetApi.options.name.type is 'string'
// greetApi.options.excited.default is false
// IntelliSense shows all available options
const options = greetApi.options
// options.name, options.excited with full type informationType Safety at Compile Time
// This will cause a TypeScript error
const invalidCommand = getCommandApi('nonexistent') // ❌
// This is type-safe
const validCommand = getCommandApi('greet') // ✅
const name = validCommand.options.name.type // 'string'Use Cases
CLI Wrappers
import { getCommandApi, listCommands } from './.bunli/commands.gen'
class CLIManager {
async executeCommand(commandName: string, options: Record<string, any>) {
const command = getCommandApi(commandName as any)
// Type-safe option validation
for (const [key, value] of Object.entries(options)) {
const option = command.options?.[key]
if (!option) throw new Error(`Unknown option: ${key}`)
if (option.type === 'string' && typeof value !== 'string') {
throw new Error(`Option ${key} must be a string`)
}
}
}
}Documentation Generation
import { listCommands, getCommandApi } from './.bunli/commands.gen'
function generateDocs() {
const commands = listCommands()
let docs = '# CLI Documentation\n\n'
for (const cmd of commands) {
const api = getCommandApi(cmd)
docs += `## ${cmd}\n${api.description}\n\n`
if (api.options) {
docs += '### Options\n'
for (const [name, option] of Object.entries(api.options)) {
docs += `- \`--${name}\` (${option.type}) ${option.description}\n`
}
}
}
return docs
}Default Behavior
Type generation uses these sensible defaults:
| Setting | Default | Description |
|---|---|---|
| Commands Directory | ./commands | Where to find command files |
| Output File | ./.bunli/commands.gen.ts | Generated types location |
| Auto-Generation | true | Always enabled |
| Watch Mode | true in dev | Regenerate on file changes |
Custom Commands Directory
If your commands are in a different location:
export default defineConfig({
name: 'my-cli',
version: '1.0.0',
commands: {
directory: './src/commands' // Custom commands location
}
})Integration with CLI Commands
Development Mode
Type generation is automatically integrated with bunli dev:
# Start development with automatic type generation
bunli dev
# Type generation runs automatically when commands changeBuild Process
Types are generated before building:
# Build includes type generation
bunli build
# Types are generated automatically before compilationManual Generation
Generate types manually when needed:
# Generate types once
bunli generate
# Generate and watch for changes
bunli generate --watch
## Advanced Features
### Type Utilities
```typescript
import { UnionToIntersection, MergeAll, Expand } from '@bunli/core'
// Use with generated types
type AllCommandOptions = UnionToIntersection<
CommandRegistry[keyof CommandRegistry]['options']
>Build Integration
// bunli.config.ts
import { defineConfig } from '@bunli/core'
export default defineConfig({
name: 'my-cli',
version: '1.0.0',
build: {
entry: './src/cli.ts',
outdir: './dist'
}
})Best Practices
Import Generated Types: Always import generated types for full type safety.
File Organization
src/
├── commands/
│ ├── greet.ts
│ └── deploy.ts
├── .bunli/
│ └── commands.gen.ts # Generated file
├── cli.ts
└── bunli.config.tsDevelopment Workflow
- Configure: Set up
bunli.config.ts - Generate: Run
bunli generateorbunli dev - Use: Import generated types in your code
- Build: Run
bunli build(types generated automatically)
Troubleshooting
Types not updating:
- Run
bunli generate --watchfor development - Check command files are in the correct directory
Import errors:
- Ensure generated file exists at
./.bunli/commands.gen.ts - Verify TypeScript configuration includes
.bunli/**/*.ts
Missing command metadata:
- Ensure commands use
defineCommand - Check commands are properly exported
Type-Safe Command Execution
import { createCLI } from '@bunli/core'
const cli = await createCLI(config)
// ✅ Fully type-safe execution!
await cli.execute('deploy', {
env: 'production', // ← Autocomplete: 'dev' | 'staging' | 'prod'
dryRun: true // ← Type: boolean
})
// ❌ Type errors for invalid options
await cli.execute('deploy', {
env: 'invalid', // ❌ Error: Type '"invalid"' is not assignable
dryRun: 'yes' // ❌ Error: Type 'string' is not assignable to type 'boolean'
})Requirements
as constRequired - Command names MUST useas constfor type inference- Generated File Required -
.bunli/commands.gen.tsmust be intsconfig.json - No Manual Annotations - Handler type annotations are automatic
See Also
- Type Inference - Runtime type inference
- Configuration - CLI configuration options
- @bunli/generator - Generator package documentation
- bunli CLI - CLI toolchain commands