Operands are positional arguments that typically represent files, URLs, or other data your CLI tool operates on. This guide covers how to work with operands and the expectOperands configuration option.
- What Are Operands?
- Default Behavior (expectOperands: true)
- Disabling Operands (expectOperands: false)
- Type Safety Benefits
- When to Use Each Approach
- Examples
Operands are positional arguments that come after flags and options. They're commonly used for:
- File paths:
my-tool --verbose file1.txt file2.txt - URLs:
download-tool --format json https://api.example.com - Commands:
git clone --depth 1 repo-url
By default, expectOperands is true, meaning your CLI accepts operands.
const cli = await parseCliArguments(
'file-processor',
{},
{
verbose: booleanArgument({
description: 'Enable verbose output',
character: 'v'
})
}
// expectOperands defaults to true
)
// cli.operands has type: string[]
console.log('Files to process:', cli.operands)
cli.operands.forEach((file) => processFile(file))Features:
cli.operandshas typestring[]- Help message includes operands in usage line
- Supports
--separator to explicitly separate arguments from operands - Runtime validation allows operands
When your CLI only works with flags and arguments, set expectOperands: false.
const cli = await parseCliArguments(
'config-tool',
{},
{
validate: booleanArgument({
description: 'Validate configuration'
}),
config: stringArgument({
description: 'Configuration file path'
})
},
{
expectOperands: false // No operands allowed
}
)
// cli.operands has type: never
// ❌ TypeScript compilation error:
// console.log(cli.operands) // Cannot access property of 'never'Features:
cli.operandshas typenever(cannot be accessed)- Help message excludes operands from usage line
- Runtime validation rejects any operands
- Compile-time type safety prevents operand access
const cli = await parseCliArguments(/* ... */)
// ✅ These work fine:
cli.operands.length // number
cli.operands.forEach(...) // OK
const files = cli.operands // string[]const cli = await parseCliArguments(/* ... */, { expectOperands: false })
// ❌ TypeScript compilation errors:
cli.operands.length // Error: Cannot read property of 'never'
cli.operands.forEach(...) // Error: Cannot read property of 'never'
const files = cli.operands // Error: Type 'never' not assignableThis compile-time protection prevents bugs where you might accidentally try to process operands that shouldn't exist.
- File processing tools:
my-tool file1.txt file2.txt - URL downloaders:
fetch-tool url1 url2 url3 - Package managers:
install package1 package2 - Compilers:
compiler source1.ts source2.ts
- Configuration tools:
config-tool --validate --format json - Status checkers:
health-check --endpoint api --timeout 30 - Initializers:
init-tool --template react --typescript - Utilities that work entirely with flags:
cleanup --force --dry-run
// Example: my-tool --verbose --output dist/ file1.txt file2.txt
const cli = await parseCliArguments(
'file-processor',
{},
{
verbose: booleanArgument({ description: 'Verbose output', character: 'v' }),
output: stringArgument({ description: 'Output directory' })
}
// expectOperands defaults to true
)
if (cli.operands.length === 0) {
console.log('No input files provided')
process.exit(1)
}
cli.operands.forEach((file) => {
if (cli.args.verbose) {
console.log(`Processing ${file}...`)
}
processFile(file, cli.args.output)
})// Example: config-tool --validate --config settings.json
const cli = await parseCliArguments(
'config-tool',
{},
{
validate: booleanArgument({ description: 'Validate only', character: 'c' }),
config: stringArgument({ description: 'Config file path' }),
format: stringArgument({ description: 'Output format', defaultValue: 'table' })
},
{
expectOperands: false // Only flags and options
}
)
// No need to check operands - they can't exist!
// cli.operands is not accessible at compile time
const configPath = cli.args.config || './config.json'
const config = loadConfig(configPath)
if (cli.args.validate) {
validateConfig(config, cli.args.format)
} else {
runWithConfig(config)
}When users provide operands to a CLI with expectOperands: false, they get clear error messages:
$ config-tool --validate extra-arg
# Error: Operands are not expected but received: extra-arg
$ config-tool --config settings.json file1.txt file2.txt
# Error: Operands are not expected but received: file1.txt, file2.txtWith expectOperands: true:
Usage: file-processor [options] [flags] [--] [operand1] [operand2]
With expectOperands: false:
Usage: config-tool [options] [flags]
- Choose the right default: Most CLIs expect operands, so the default is usually correct
- Be explicit when disabling: If your tool doesn't need operands, explicitly set
expectOperands: false - Use descriptive operand names: Set
operandsNameto something meaningful like "files", "urls", or "packages" - Validate operand count: Check if you have the right number of operands when using
expectOperands: true - Leverage type safety: Let TypeScript prevent operand-related bugs at compile time
- API Reference - Complete API documentation
- Examples - Working examples including operands.ts and noOperands.ts
- Getting Started - Basic CLI setup