Skip to content

Types

Types allow you to validate, convert, and parse values for both flags and parameters. Clerc provides several built-in type functions and supports custom types.

Built-in Basic Types

Clerc supports the standard JavaScript type constructors for common use cases:

  • String: For string values (default value: undefined)
  • Number: For numeric values (can be used directly)
  • Boolean: For boolean switches (default value: false)
  • Object: For key-value pairs (default value: {})

String Type

The String type is used for flags and parameters that accept string values. This is the most basic type.

Default value behavior: If not specified, its value is undefined (unless a default property is set).

ts
const 
cli
=
Cli
()
.
command
("greet", "Greet someone", {
flags
: {
name
: {
type
:
String
,
description
: "User name",
default
: "World",
},
message
: {
type
:
String
,
short
: "m",
description
: "Greeting message",
}, }, }) .
on
("greet", (
ctx
) => {
console
.
log
(`${
ctx
.
flags
.
message
}, ${
ctx
.
flags
.
name
}!`);
// $ node cli.mjs greet --name John --message Hello // Hello, John! // $ node cli.mjs greet --message Hello // ctx.flags.message => "Hello" // ctx.flags.name => "World" (uses default value) }) .
parse
();

Boolean Type

The Boolean type is used for creating boolean switch flags. By default, simply mentioning the flag name sets it to true.

Default value behavior: If the flag is not specified, its value is false.

ts
const 
cli
=
Cli
()
.
command
("build", "Build the project", {
flags
: {
production
: {
type
:
Boolean
,
description
: "Build for production",
},
watch
: {
type
:
Boolean
,
short
: "w",
description
: "Enable watch mode",
}, }, }) .
on
("build", (
ctx
) => {
// $ node cli.mjs build --production --watch
ctx
.
flags
.
production
; // => true
ctx
.
flags
.
watch
; // => true
// $ node cli.mjs build
ctx
.
flags
.
production
; // => false
ctx
.
flags
.
watch
; // => false
}) .
parse
();

Boolean's Negatable Property

The Boolean type supports a negatable property that allows you to decide whether to enable negated flags. By default, negatable is true, which means --no-flag will set the flag flag to false.

ts
const 
cli
=
Cli
()
.
command
("start", "Start the application", {
flags
: {
color
: {
type
:
Boolean
,
negatable
: true, // default
description
: "Enable color output",
default
: true,
},
cache
: {
type
:
Boolean
,
negatable
: false, // disable negation form
description
: "Enable caching",
default
: true,
}, }, }) .
on
("start", (
ctx
) => {
// $ node cli.mjs start
ctx
.
flags
.
color
; // => true
ctx
.
flags
.
cache
; // => true
// $ node cli.mjs start --no-color --no-cache
ctx
.
flags
.
color
; // => false
ctx
.
flags
.
cache
; // => true
// You must use --cache=false to disable caching // $ node cli.mjs start --cache=false
ctx
.
flags
.
cache
; // => false
}) .
parse
();

Array Type

The Array type is used for flags and parameters that accept multiple values. Define it by wrapping the type function in an array:

Default value behavior: If not specified, its value is [] (empty array).

ts
const 
cli
=
Cli
()
.
command
("copy", "Copy files", {
flags
: {
// Use [String] to accept multiple string values
include
: {
type
: [
String
],
short
: "i",
description
: "File patterns to include",
}, // Use [Number] to accept multiple numeric values
ports
: {
type
: [
Number
],
short
: "p",
description
: "Ports to listen on",
}, }, }) .
on
("copy", (
ctx
) => {
// $ node cli.mjs copy -i "*.js" -i "*.ts" -p 3000 -p 3001
ctx
.
flags
.
include
; // => ["*.js", "*.ts"]
ctx
.
flags
.
ports
; // => [3000, 3001]
// $ node cli.mjs copy
ctx
.
flags
.
include
; // => []
ctx
.
flags
.
ports
; // => []
}) .
parse
();

Counter Type

The counter type is used to count how many times a flag is specified. This can be implemented by using the [Boolean] type:

Default value behavior: If not specified, its value is 0.

ts
const 
cli
=
Cli
()
.
command
("log", "Display logs", {
flags
: {
// [Boolean] type counts how many times the flag is used
verbose
: {
type
: [
Boolean
],
short
: "v",
description
: "Verbosity level (-v, -vv, -vvv)",
}, }, }) .
on
("log", (
ctx
) => {
// $ node cli.mjs log -v
ctx
.
flags
.
verbose
; // => 1
// $ node cli.mjs log -vvv
ctx
.
flags
.
verbose
; // => 3
// $ node cli.mjs log -v -v -v
ctx
.
flags
.
verbose
; // => 3
// $ node cli.mjs log
ctx
.
flags
.
verbose
; // => 0
}) .
parse
();

Object Type

The Object type is used for flags that accept key-value pairs. Use dots or other delimiters to specify object properties:

Default value behavior: If not specified, its value is {} (empty object).

ts
const 
cli
=
Cli
()
.
command
("config", "Configure the application", {
flags
: {
define
: {
type
:
Object
,
short
: "d",
description
: "Define environment variables",
}, }, }) .
on
("config", (
ctx
) => {
// $ node cli.mjs config --define.apiUrl http://api.example.com --define.debug
ctx
.
flags
.
define
; // => { apiUrl: "http://api.example.com", debug: true }
// $ node cli.mjs config
ctx
.
flags
.
define
; // => {}
}) .
parse
();

INFO

If you want to pass key-value pairs like K=V, you can use the colon delimiter in the command line:

bash
$ node cli.mjs config --define:env=production --define:version=1.0.0

Actually, --define=env=production also works fine, it's just not as intuitive.

Built-in Advanced Types

Clerc provides some built-in advanced type functions to facilitate common needs:

  • Enum: Restrict flag and parameter values to a predefined set.
  • Range: Restrict numeric values to a specific range and convert to numbers.
  • Regex: Validate values against a regular expression pattern.

These type functions can be used for both flags and parameters, allowing you to share the same type definitions across your CLI:

ts
import { 
Types
} from "clerc";
Cli
()
.
command
("serve", "Start the server", {
flags
: {
mode
: {
type
:
Types
.
Enum
("development", "production", "test"),
default
: "development" as
const
,
description
: "Set the application mode",
}, },
parameters
: [
{
key
: "[port]",
type
:
Types
.
Range
(1024, 65_535),
description
: "Port number",
}, ], }) .
on
("serve", (
ctx
) => {
ctx
.
flags
.
mode
;
ctx
.
parameters
.
port
;
}) .
parse
();

Enum Type

Restrict flag or parameter values to a predefined set of options:

ts
import { 
Types
} from "clerc";
const
cli
=
Cli
()
.
scriptName
("build-cli")
.
description
("Build tool")
.
version
("1.0.0")
.
command
("config", "Configure build settings", {
flags
: {
format
: {
type
:
Types
.
Enum
("json", "yaml", "toml"),
description
: "Output format",
}, },
parameters
: [
{
key
: "<setting>",
type
:
Types
.
Enum
("output", "target", "format"),
description
: "Setting name",
}, {
key
: "<value>",
description
: "Setting value",
}, ], }) .
on
("config", (
ctx
) => {
console
.
log
(`Setting ${
ctx
.
parameters
.
setting
} = ${
ctx
.
parameters
.
value
}`);
}) .
parse
();

Usage:

bash
$ build-cli config --format json output dist
$ build-cli config --format yaml target es2020
$ build-cli config --format invalid value
# Error: Invalid value: invalid. Must be one of: json, yaml, toml

Range Type

Restrict numeric values to a specific range and convert to numbers:

ts
import { 
Types
} from "clerc";
const
cli
=
Cli
()
.
scriptName
("server-cli")
.
description
("Server management tool")
.
version
("1.0.0")
.
command
("start", "Start the server", {
flags
: {
port
: {
type
:
Types
.
Range
(1024, 65_535),
description
: "Port number",
}, },
parameters
: [
{
key
: "[timeout]",
type
:
Types
.
Range
(1, 3600),
description
: "Timeout in seconds",
}, ], }) .
on
("start", (
ctx
) => {
const
port
=
ctx
.
flags
.
port
?? 3000;
console
.
log
(`Starting server on port ${
port
}`);
}) .
parse
();

Usage:

bash
$ server-cli start --port 3000
$ server-cli start --port 8080
$ server-cli start --port 100
# Error: Invalid value: 100. Must be a number between 1024 and 65535

Regex Type

Validate values against a regular expression pattern:

ts
import { 
Types
} from "clerc";
const
cli
=
Cli
()
.
scriptName
("git-clone")
.
description
("Clone repository")
.
version
("1.0.0")
.
command
("clone", "Clone a repository", {
parameters
: [
{
key
: "<repo>",
type
:
Types
.
Regex
(/^[\w\-.]+\/[\w\-.]+$/, "owner/repo format"),
description
: "Repository in owner/repo format",
}, ], }) .
on
("clone", (
ctx
) => {
console
.
log
(`Cloning ${
ctx
.
parameters
.
repo
}`);
}) .
parse
();

Usage:

bash
$ git-clone clone clercjs/clerc
$ git-clone clone myorg/myrepo
$ git-clone clone invalid
# Error: Invalid value: invalid. Must match: owner/repo format

Custom Types

You can create custom type functions by providing a function that accepts a string argument and returns the parsed value.

Type Display Property

Custom type functions can include an optional display property that provides a user-friendly name for the type in help output. This is especially useful for complex types where the function name doesn't clearly describe what the type accepts.

ts
// Custom type function that parses a comma-separated string into an array of strings
const 
CommaSeparatedList
= (
value
: string): string[] =>
value
.
split
(",").
map
((
item
) =>
item
.
trim
());
// Add a display property for better help documentation
CommaSeparatedList
.
display
= "item1,item2,...";
const
cli
=
Cli
()
.
scriptName
("custom-cli")
.
description
("A CLI using a custom type")
.
version
("1.0.0")
.
command
("list", "Display list", {
flags
: {
items
: {
type
:
CommaSeparatedList
,
default
: [] as string[],
description
: "Comma-separated list of strings",
}, }, }) .
on
("list", (
ctx
) => {
console
.
log
("Items:",
ctx
.
flags
.
items
);
}) .
parse
();

The display property is used by the help system to show a more descriptive type name instead of the function name. For example, instead of showing "CommaSeparatedList" in the help output, it would show "item1,item2,...".

Basic Custom Type Example

ts
// Custom type function that parses a comma-separated string into an array of strings
const 
CommaSeparatedList
= (
value
: string): string[] =>
value
.
split
(",").
map
((
item
) =>
item
.
trim
());
const
cli
=
Cli
()
.
scriptName
("custom-cli")
.
description
("A CLI using a custom type")
.
version
("1.0.0")
.
command
("list", "Display list", {
flags
: {
items
: {
type
:
CommaSeparatedList
,
default
: [] as string[],
description
: "Comma-separated list of strings",
}, }, }) .
on
("list", (
ctx
) => {
console
.
log
("Items:",
ctx
.
flags
.
items
);
}) .
parse
();

Custom type functions can also be used with array syntax to accept multiple values:

ts
const 
cli
=
Cli
()
.
command
("process", "Process files", {
flags
: {
// Use [CommaSeparatedList] to accept multiple comma-separated lists
patterns
: {
type
: [CommaSeparatedList],
short
: "p",
description
: "File patterns (comma-separated)",
}, }, }) .
on
("process", (
ctx
) => {
// $ node cli.mjs process -p "*.js,*.ts" -p "src/**"
ctx
.
flags
.
patterns
; // => [["*.js", "*.ts"], ["src/**"]]
}) .
parse
();

Using Custom Types with Parameters

Custom type functions with display properties can also be used for parameters, providing better help documentation:

ts
// Custom type function for parsing version numbers
function 
Version
(
value
: string): string {
if (!/^\d+\.\d+\.\d+$/.
test
(
value
)) {
throw new
Error
(`Invalid version format: ${
value
}. Expected format: x.y.z`);
} return
value
;
} // Add display property for help documentation
Version
.
display
= "x.y.z";
const
cli
=
Cli
()
.
scriptName
("release-cli")
.
description
("Release management tool")
.
version
("1.0.0")
.
command
("publish", "Publish a new version", {
parameters
: [
{
key
: "<version>",
type
:
Version
,
description
: "Version number to publish",
}, {
key
: "[channel]",
type
: Types.Enum("stable", "beta", "alpha"),
description
: "Release channel",
}, ], }) .
on
("publish", (
ctx
) => {
console
.
log
(
`Publishing version ${
ctx
.
parameters
.version} to ${
ctx
.
parameters
.channel || "stable"} channel`,
); }) .
parse
();

In the help output, instead of showing "Version" as the type, it will show "x.y.z", making it clearer what format is expected.

Released under the MIT license