> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cbrock.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Primitive Guards

> Guards for strings, numbers, booleans, and other primitives.

## `is.string`

Validates that a value is a `string`. Chain helpers directly on `is.string` to refine or transform the value.

```typescript theme={null}
import { is } from 'ts-chas/guard';

is.string('hello'); // true
is.string(123);     // false
```

### Format validators

| Helper              | Guard Type | Validates                                                               |
| ------------------- | ---------- | ----------------------------------------------------------------------- |
| `.email`            | Property   | RFC 5322 email address                                                  |
| `.url`              | Property   | Any WHATWG-compliant URL string                                         |
| `.httpUrl`          | Property   | URL with `http:` or `https:` protocol                                   |
| `.uuid(options?)`   | Factory    | UUID (any version by default); pass `version: 'v4'` to pin to a version |
| `.uuidv4`           | Property   | Shorthand for UUID v4                                                   |
| `.uuidv6`           | Property   | Shorthand for UUID v6                                                   |
| `.uuidv7`           | Property   | Shorthand for UUID v7                                                   |
| `.ulid`             | Property   | ULID (26-character lexicographically sortable ID)                       |
| `.nanoid(options?)` | Factory    | NanoID; default length 21, override with `length: n`                    |
| `.ipv4`             | Property   | IPv4 address                                                            |
| `.ipv6`             | Property   | IPv6 address                                                            |
| `.cidrv4`           | Property   | IPv4 CIDR block (e.g. `192.168.1.0/24`)                                 |
| `.cidrv6`           | Property   | IPv6 CIDR block (e.g. `2001:db8::/32`)                                  |
| `.mac(options?)`    | Factory    | MAC address; delimiter defaults to `:`, pass \`delimiter: '-'           |
| `.emoji`            | Property   | Contains at least one emoji character                                   |
| `.uppercase`        | Property   | All characters are uppercase                                            |
| `.lowercase`        | Property   | All characters are lowercase                                            |

```typescript theme={null}
const uuidGuard = is.string.uuid({ version: 'v7' });
uuidGuard.parse('01952870-7580-7b7e-8eef-7d7e7e7e7e7e'); // Ok(string)

const macGuard = is.string.mac({ delimiter: '-' });
macGuard('AA-BB-CC-DD-EE-FF'); // true
```

### Length and content

| Helper             | Guard Type | Validates                  |
| ------------------ | ---------- | -------------------------- |
| `.min(n)`          | Factory    | Length ≥ n                 |
| `.max(n)`          | Factory    | Length ≤ n                 |
| `.length(n)`       | Factory    | Exact length of n          |
| `.regex(re)`       | Factory    | Matches regular expression |
| `.includes(str)`   | Factory    | Contains substring         |
| `.startsWith(str)` | Factory    | Starts with prefix         |
| `.endsWith(str)`   | Factory    | Ends with suffix           |

```typescript theme={null}
const slug = is.string.min(1).max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
slug.parse('my-post-title'); // Ok('my-post-title')
slug.parse('');              // Err(...)
```

### Encoding validators

| Helper              | Guard Type | Validates                                                                                             |
| ------------------- | ---------- | ----------------------------------------------------------------------------------------------------- |
| `.base64(options?)` | Factory    | Base64 encoding; options: `padding: 'required' or 'optional' or 'forbidden'`                          |
| `.hex(options?)`    | Factory    | Hex encoding; options: `prefix?: boolean, evenLength?: boolean, case?: 'lower' or 'upper' or 'mixed'` |
| `.jwt(options?)`    | Factory    | JWT structure; options: `validateJson?: boolean, alg?: string or string[]`                            |

```typescript theme={null}
const hexColor = is.string.hex({ evenLength: true, case: 'lower' });
hexColor.parse('ff0099'); // Ok('ff0099')
hexColor.parse('FF0099'); // Err(...)

const jwt = is.string.jwt({ alg: ['HS256', 'RS256'] });
jwt('eyJhbGciOiJIUzI1NiJ9.e30.abc'); // true (structure only — not signature verification)
```

### Hash validation

`.hash(options?)` validates a cryptographic hash string using `@noble/hashes`. Works in browser, Node.js, and edge runtimes.

**Options:**

* `alg` — `'sha1' | 'sha256' | 'sha384' | 'sha512' | 'md5'` (default: `'sha256'`)
* `enc` — `'hex' | 'base64' | 'base64url'` (default: `'hex'`)
* `padding` — `'required' | 'optional' | 'forbidden'` (only relevant for base64/base64url)

Chain `.verify(plaintext)` after `.hash()` for a timing-safe comparison that re-hashes the plaintext and compares.

```typescript theme={null}
import { is } from 'ts-chas/guard';

// Validate a SHA-256 hex digest
const sha256Hex = is.string.hash({ alg: 'sha256', enc: 'hex' });
sha256Hex('b94d27b9934d3e08...'); // true if correct length and hex chars

// Timing-safe verification against known plaintext
const verifyPassword = is.string.hash({ alg: 'sha256', enc: 'hex' }).verify('mysecret');
verifyPassword.parse(storedHash); // Ok(string) if storedHash matches sha256('mysecret')
```

### JSON validators

```typescript theme={null}
// Validates the string is parseable JSON
const jsonStr = is.string.json({ type: 'object', maxDepth: 5 });
jsonStr.parse('{"a":1}'); // Ok('{"a":1}') — still typed as string

// Parses JSON and validates the result — output type changes
const parsedUser = is.string.parsedJson({
  schema: is.object({ id: is.number, name: is.string }),
  type: 'object',
});
parsedUser.parse('{"id":1,"name":"Alice"}'); // Ok({ id: 1, name: 'Alice' })
```

### ISO date and time

Access sub-validators through `.iso`:

| Helper                    |                      | Validates                                                                                         |
| ------------------------- | -------------------- | ------------------------------------------------------------------------------------------------- |
| `.iso`                    | Transformer Property | Any ISO 8601 string                                                                               |
| `.iso.date`               | Transformer Property | Date only: `YYYY-MM-DD`                                                                           |
| `.iso.time(options?)`     | Transformer Factory  | Time: `HH:MM` or `HH:MM:SS[.s+]`; `{ precision: -1 }` for minute-only                             |
| `.iso.datetime(options?)` | TRansformer Factory  | Full datetime with timezone; `{ offset: false }` forbids it, `{ local: true }` allows unqualified |

```typescript theme={null}
const eventDate = is.string.iso.date;
eventDate.parse('2026-03-30'); // Ok('2026-03-30')
eventDate.parse('March 30');   // Err(...)

const timestamp = is.string.iso.datetime({ precision: 3 }); // requires milliseconds
timestamp.parse('2026-03-30T12:00:00.000Z'); // Ok(...)
```

### Transformers

Transformers modify the value as it flows through the chain. Subsequent validators operate on the transformed value.

| Helper                 | Guard Type          | Transforms                                  |
| ---------------------- | ------------------- | ------------------------------------------- |
| `.trim()`              | Transformer Factory | Removes leading and trailing whitespace     |
| `.toLowerCase()`       | Transformer Factory | Converts to lowercase                       |
| `.toUpperCase()`       | Transformer Factory | Converts to uppercase                       |
| `.normalize(options?)` | Transformer Factory | Unicode normalization; default form `'NFC'` |

```typescript theme={null}
const email = is.string.trim().toLowerCase().email.max(255);
email.parse('  ALICE@EXAMPLE.COM  '); // Ok('alice@example.com')
```

### Boolean strings

`.boolStr` validates strings that represent boolean values. It is case-insensitive by default and accepts:

* **Truthy:** `true`, `1`, `yes`, `y`, `on`, `active`, `enabled` (and their capitalised/uppercase variants)
* **Falsy:** `false`, `0`, `no`, `n`, `off`, `inactive`, `disabled` (and their capitalised/uppercase variants)

Chain `.truthy(options?)` or `.falsy(options?)` to accept only one side. Chain `.asBool` to transform the string to a `boolean`. Pass `{ values: [...strings] }` into `.truthy()` or `.falsy()` to use a custom allowlist.

```typescript theme={null}
const flag = is.string.boolStr;
flag('yes');   // true
flag('0');     // true
flag('maybe'); // false

const asBoolean = is.string.boolStr.asBool;
asBoolean.parse('yes');  // Ok(true)
asBoolean.parse('false'); // Ok(false)

const isMaybeStr = is.string.boolStr.truthy({ values: ['maybe', 'idk'] });
flag('maybe'); // true
flag('no'); // false
```

***

## `is.number`

Validates that a value is a `number` (not `NaN`).

```typescript theme={null}
is.number(42);    // true
is.number('42');  // false
is.number(NaN);   // false — use is.nan for NaN
```

### Helpers

| Helper               | Guard Type | Validates                        |
| -------------------- | ---------- | -------------------------------- |
| `.int`               | Property   | Safe integer (no decimal part)   |
| `.positive`          | Property   | Greater than 0                   |
| `.negative`          | Property   | Less than 0                      |
| `.finite`            | Property   | Not `Infinity` or `-Infinity`    |
| `.safe`              | Property   | Within `Number.MAX_SAFE_INTEGER` |
| `.even`              | Property   | Divisible by 2                   |
| `.odd`               | Property   | Not divisible by 2               |
| `.gt(n)`             | Factory    | Greater than n                   |
| `.gte(n)`            | Factory    | Greater than or equal to n       |
| `.lt(n)`             | Factory    | Less than n                      |
| `.lte(n)`            | Factory    | Less than or equal to n          |
| `.between(min, max)` | Factory    | Inclusive range                  |
| `.eq(n)`             | Factory    | Strictly equal to n              |
| `.multipleOf(n)`     | Factory    | Divisible by n with no remainder |

```typescript theme={null}
const port = is.number.int.between(1, 65535);
port.parse(8080); // Ok(8080)
port.parse(0);    // Err(...)

const even100 = is.number.int.multipleOf(2).lte(100);
even100.parse(42); // Ok(42)
even100.parse(43); // Err(...)
```

***

## `is.boolean`

Validates that a value is `true` or `false`.

| Helper   | Guard Type | Validates       |
| -------- | ---------- | --------------- |
| `.true`  | Property   | Exactly `true`  |
| `.false` | Property   | Exactly `false` |

```typescript theme={null}
is.boolean(true);       // true
is.boolean.true(false); // false
is.boolean.false(false); // true
```

***

## Other primitives

| Guard          | Validates                     |
| -------------- | ----------------------------- |
| `is.bigint`    | BigInt values                 |
| `is.symbol`    | Symbol values                 |
| `is.null`      | `null`                        |
| `is.undefined` | `undefined`                   |
| `is.void`      | `null` or `undefined`         |
| `is.nan`       | `NaN` (branded as `NaN` type) |

```typescript theme={null}
is.bigint(42n);        // true
is.null(null);         // true
is.void(undefined);    // true
is.void(null);         // true
is.nan(NaN);           // true
is.nan(0);             // false
```

***

## Type-only guards

Unknown and any always pass at runtime and all three narrow the TypeScript type.

| Guard        | Type                              |
| ------------ | --------------------------------- |
| `is.unknown` | `unknown`                         |
| `is.any`     | `any`                             |
| `is.never`   | `never` (always fails at runtime) |

***

## `is.literal(...values)`

Validates strict equality against one or more literal values. Uses `Object.is` semantics, so it correctly handles `NaN` and distinguishes `0` from `-0`.

```typescript theme={null}
const status = is.literal('active', 'inactive', 'pending');
status('active');  // true
status('deleted'); // false

const mixed = is.literal(1, 'hello', true, null);
mixed(1);     // true
mixed(false); // false
```

## `is.templateLiteral(...)`

Validates that a string matches a template literal pattern. Accepts a mix of string segments and guards for interpolated positions.

```typescript theme={null}
const route = is.templateLiteral('/users/', is.number);
route('/users/42');    // true
route('/users/abc');   // false

const method = is.templateLiteral(is.literal('GET', 'POST'), '://', is.string);
method('GET://api.example.com'); // true
method('DELETE://api.example.com'); // false
```

***

***

## `is.enum(values)`

Validates that a value is one of the members of an array, TypeScript enum, or object literal.

```typescript theme={null}
// Array of values
const Direction = is.enum(['north', 'south', 'east', 'west'] as const);
Direction('north'); // true
Direction('up');    // false

// TypeScript enum
enum Color { Red, Green, Blue }
const color = is.enum(Color);
color(Color.Red); // true

// Object literal
const sizes = is.enum({ SM: 'sm', MD: 'md', LG: 'lg' });
sizes('sm'); // true
```

| Helper             | Guard Type          | Validates                                      |
| :----------------- | :------------------ | ---------------------------------------------- |
| `.exclude(values)` | Transformer Factory | Excludes applicable<br />values from the enum. |
| `.extract(values)` | Transformer Factory | Extracts only specific values from the enum    |
