> ## 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.

# Object & Collection Guards

> Guards for objects, arrays, records, tuples, and built-in types.

## `is.object({ ... })`

Validates that a value is a plain object whose fields satisfy the provided shape. Fields not listed in the shape are allowed by default.

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

const PersonGuard = is.object({
  name: is.string.min(1),
  age:  is.number.int.gte(0),
});

PersonGuard({ name: 'Alice', age: 30 });           // true
PersonGuard({ name: 'Alice', age: 30, role: 'admin' }); // true — extra key allowed
PersonGuard({ name: '', age: 30 });                // false
```

### Helpers

`.strict` (Transformer Property) — disallows extra keys not listed in the shape.

```typescript theme={null}
const Strict = is.object({ id: is.number }).strict;
Strict({ id: 1, extra: true }); // false
```

`.partial()` (Transformer Factory) — makes all fields optional (`T | undefined`). If an array of keys is passed as argument, only those keys become optional.

```typescript theme={null}
const Patch = is.object({ name: is.string, age: is.number }).partial();
Patch({});           // true, all fields are now optional
Patch({ name: 'x' }); // true
```

`.required()` (Transformer Factory) — makes all fields required. If an array of keys is passed as argument, only those keys become required.

```typescript theme={null}
const Patch = is.object({ name: is.string, age: is.number }).required();
Patch({ name: 'Chase', age: 999 });  // true, all fields are now required
Patch({ name: 'x' }); // false
```

`.pick([keys])` (Transformer Factory) — keeps only the listed keys.

```typescript theme={null}
const IdOnly = is.object({ id: is.number, name: is.string }).pick(['id']);
IdOnly({ id: 1 });         // true
IdOnly({ id: 1, name: 'x' }); // false — name is an extra key in the narrowed shape
```

`.omit([keys])` (Transformer Factory) — removes the listed keys from the shape.

```typescript theme={null}
const NoPassword = is.object({ email: is.string, password: is.string }).omit(['password']);
NoPassword({ email: 'a@b.co' }); // true
```

`.extend({ ... })` (Transformer Factory) — merges additional fields into the shape. Returns a new guard. Prefer this over the top-level `is.and()` for merging objects.

```typescript theme={null}
const Base  = is.object({ id: is.number });
const Named = Base.extend({ name: is.string });
Named({ id: 1, name: 'Alice' }); // true
```

`.catchall(innerGuard)` (Transformer Factory) — allows any extra keys not defined in the schema, but only if they satisfy the provided guard.

```typescript theme={null}
const Base  = is.object({ id: is.number });
const Named = Base.extend({ name: is.string });
Named({ id: 1, name: 'Alice' }); // true
```

### Other object helpers

| Helper              | Guard Type          | Validates                                                  |
| :------------------ | ------------------- | :--------------------------------------------------------- |
| `.size(n)`          | Factory             | Size = n                                                   |
| `.minSize(n)`       | Factory             | Size ≥ n                                                   |
| `.maxSize(n)`       | Factory             | Size ≤ n                                                   |
| `.has(key, guard?)` | Transformer Factory | Object has property that (optionally) satisfies<br />guard |
| `.hasAll(keys)`     | Factory             | Object has all specified keys                              |
| `.hasOnly(keys)`    | Factory             | Object has only the specified keys                         |

***

## `is.array(guard?)`

Validates that a value is an array. Pass one or more element guards to validate every item.

```typescript theme={null}
is.array()([1, 'two', true]); // true — unknown[]
is.array(is.number)([1, 2, 3]); // true — number[]
is.array(is.string, is.number)(['a', 1]); // true — (string | number)[]
```

### Helpers

| Helper            | Guard Type           | Validates                                                               |
| ----------------- | -------------------- | ----------------------------------------------------------------------- |
| `.min(n)`         | Factory              | Length ≥ n                                                              |
| `.max(n)`         | Factory              | Length ≤ n                                                              |
| `.length(n)`      | Factory              | Length = n                                                              |
| `.nonEmpty`       | Property             | Length ≥ 1                                                              |
| `.unique`         | Property             | Every element is unique                                                 |
| `.includes(item)` | Factory              | Array contains item                                                     |
| `.excludes(item)` | Factory              | Array does not contain item                                             |
| `.readonly`       | Transformer Property | Wraps array in Object.freeze(), returns readonly<br />array when parsed |

```typescript theme={null}
const tags = is.array(is.string).nonEmpty.max(10);
tags.parse(['typescript', 'validation']); // Ok(string[])
tags.parse([]);                           // Err(...)
```

***

## `is.record(keyGuard, valueGuard)`

Validates that a value is a plain object where every key and value satisfies the provided guards.

When `keyGuard` has a **finite** set of values (`is.enum` or `is.literal`), the record performs **exhaustive key checking** — all keys must be present and no extra keys are allowed. This matches TypeScript's `Record<'a' | 'b', V>` semantics.

When `keyGuard` is **open-ended** (`is.string`, `is.number`), it validates that every existing key/value pair satisfies the guards without requiring any specific keys.

```typescript theme={null}
// Open-ended — any string key is fine
const scores = is.record(is.string, is.number);
scores({ alice: 90, bob: 85 }); // true
scores({ alice: 'A' });         // false — value must be number

// Exhaustive — all keys must be present, no extras
const Flags = is.record(is.literal('darkMode', 'beta'), is.boolean);
Flags({ darkMode: true, beta: false }); // true
Flags({ darkMode: true });              // false — 'beta' is missing
```

`is.record` has all of the same helpers as [is.object](#is-object--)

***

## `is.tuple([...], restGuard?)`

Validates a fixed-length array where each position has its own guard. Pass a second argument to allow variadic trailing elements.

```typescript theme={null}
// Fixed length
const Point = is.tuple([is.number, is.number]);
Point([10, 20]);     // true
Point([10, 20, 30]); // false — too many elements

// With rest elements
const Args = is.tuple([is.string], is.number);
Args(['cmd']);            // true — rest is optional
Args(['cmd', 1, 2, 3]);  // true — [string, ...number[]]
Args(['cmd', 'nope']);    // false — rest element must be number
```

| Helper            | Guard Type           | Validates                                                  |
| :---------------- | :------------------- | :--------------------------------------------------------- |
| `.nonEmpty`       | Property             | Tuple is not empty                                         |
| `.unique`         | Property             | All elements are unique                                    |
| `.min(n)`         | Factory              | Length ≥ n                                                 |
| `.max(n)`         | Factory              | Length ≤ n                                                 |
| `.size(n)`        | Factory              | Length = n                                                 |
| `.includes(item)` | Factory              | Tuple has item                                             |
| `.excludes(item)` | Factory              | Tuple does not have item                                   |
| `.readonly`       | Transformer Property | Tuples are already readonly, included<br />for consistency |

***

## `is.union(...)`, `is.intersection(...)`, `is.xor(...)`

**`is.union(...guards)`** — passes if the value satisfies **at least one** guard.

```typescript theme={null}
const StringOrNumber = is.union(is.string, is.number, is.boolean);
StringOrNumber('hello'); // true — string | number | boolean
StringOrNumber(null);    // false
```

**`is.intersection(...guards)`** — passes if the value satisfies **all** guards.

```typescript theme={null}
const Named = is.object({ name: is.string });
const Aged  = is.object({ age: is.number });
const Person = is.intersection(Named, Aged);

Person({ name: 'Alice', age: 30 }); // true — { name: string } & { age: number }
Person({ name: 'Alice' });          // false
```

**`is.xor(...guards)`** — passes if the value satisfies **exactly one** guard.

```typescript theme={null}
const XorGuard = is.xor(
  is.object({ a: is.string }),
  is.object({ b: is.number }),
);

XorGuard({ a: 'hello' });           // true — matches first only
XorGuard({ a: 'hello', b: 1 });     // false — matches both
```

***

## Built-in type guards

### `is.date`

Validates a `Date` instance.

```typescript theme={null}
const pastDate = is.date.before(new Date());
pastDate.parse(new Date('2020-01-01')); // Ok(Date)

const normalized = is.date.startOf('year');
normalized.parse(new Date('2025-06-15')); // Ok(2025-01-01T00:00:00.000Z)
```

| Helper                     | Guard Type          | Validates                                                |
| :------------------------- | ------------------- | :------------------------------------------------------- |
| `.before(date)`            | Factory             | Date is before the given date                            |
| `.after(date)`             | Factory             | Date is after the given date                             |
| `.between(min, max)`       | Factory             | Date is between min and max                              |
| `.weekend`                 | Property            | Date is a weekend                                        |
| `.weekday`                 | Property            | Date is a weekday                                        |
| `.day(dow)`                | Factory             | Date is given day of the week                            |
| `.month(num)`              | Factory             | Date has given month (0-indexed)                         |
| `.year(num)`               | Factory             | Date has given year                                      |
| `.dayOfMonth(num)`         | Factory             | Date is a specific day of the month (1-31)               |
| `.timezoneOffset(minutes)` | Factory             | Date has given timezone offset                           |
| `.hour(num)`               | Factory             | Date has specific hour                                   |
| `.minute(num)`             | Factory             | Date has specific minute                                 |
| `.second(num)`             | Factory             | Date has specific second                                 |
| `.millisecond(num)`        | Factory             | Date has specific millisecond                            |
| `.sameDayAs(date)`         | Factory             | Date is on the same calendar day as given date           |
| `.sameMonthAs(date)`       | Factory             | Date is in the same month as given date                  |
| `.sameYearAs(date)`        | Factory             | Date is in the same year as given date                   |
| `.future`                  | Property            | Date is in the future                                    |
| `.past`                    | Property            | Date is in the past                                      |
| `.today`                   | Property            | Date is today                                            |
| `.tomorrow`                | Property            | Date is tomorrow                                         |
| `.yesterday`               | Property            | Date is yesterday                                        |
| `.startOf(unit)`           | Transformer Factory | Truncates to start of `'year'`, `'month'`, `'day'`, etc. |
| `.endOf(unit)`             | Transformer Factory | Same as `.startOf` but for end of unit                   |

### `is.regexp`

Validates a `RegExp` instance. Optionally validates against a specific pattern.

```typescript theme={null}
is.regexp(/hello/); // true
is.regexp('hello'); // false

const specific = is.regexp(/^[a-z]+$/);
specific.parse(/^[a-z]+$/); // Ok(RegExp)
```

| Helper             | Guard Type | Validates                       |
| :----------------- | :--------- | :------------------------------ |
| `.global`          | Property   | Has a `g` flag                  |
| `.ignoreCase`      | Property   | Has `i` flag                    |
| `.multiline`       | Property   | Has `m` flag                    |
| `.unicode`         | Property   | Has `u` flag                    |
| `.sticky`          | Property   | Has `y` flag                    |
| `.dotAll`          | Property   | Has `s` flag                    |
| `.source(pattern)` | Factory    | Pattern matches source          |
| `.test(string)`    | Factory    | String passes value.test()      |
| `.flags(string)`   | Factory    | Has exactly the specified flags |

### `is.url`

Validates a `URL` instance (not a string — use `is.string.url` for strings).

```typescript theme={null}
is.url(new URL('https://example.com')); // true
is.url('https://example.com');          // false

const toHref = is.url.transform(u => u.href);
toHref.parse(new URL('https://example.com')); // Ok('https://example.com/')
```

| Helper               | Guard Type           | Validates                                             |
| :------------------- | :------------------- | :---------------------------------------------------- |
| `.http`              | Transformer Property | Protocol is http or https                             |
| `.https`             | Transformer Property | Protocol is strictly https                            |
| `.secure`            | Transformer Property | Same as `.https`                                      |
| `.local`             | Transformer Property | Matches localhost, 127.0.0.1, ::1                     |
| `.hasSearch`         | Transformer Property | Has a search query string                             |
| `.hasHash`           | Transformer Property | Has a hash fragment                                   |
| `.protocol(pattern)` | Factory              | Pattern matches protocol WITHOUT <br />trailing colon |
| `.hostname(pattern)` | Factory              | Pattern matches hostname                              |
| `.pathname(pattern)` | Factory              | Pattern matches pathname                              |
| `.port(n?)`          | Factory              | Port = n or is present                                |

### `is.map(keyGuard?, valueGuard?)`

Validates a `Map` instance with optional key and value guards.

```typescript theme={null}
is.map()(new Map());                                    // true
is.map(is.string, is.number)(new Map([['a', 1]]));      // true
is.map(is.string, is.number).nonEmpty(new Map([['a', 1]])); // true
is.map().size(2)(new Map([['a', 1], ['b', 2]]));        // true
```

| Helper             | Guard Type           | Validates                                  |
| :----------------- | :------------------- | :----------------------------------------- |
| `.nonEmpty`        | Property             | Size > 0                                   |
| `.empty`           | Property             | Size = 0                                   |
| `.size(num)`       | Factory              | Size = num                                 |
| `.minSize(num)`    | Factory              | Size ≥ num                                 |
| `.maxSize(num)`    | Factory              | Size ≤ num                                 |
| `.hasKey(key)`     | Factory              | Contains key                               |
| `.hasValue(value)` | Factory              | Contains value                             |
| `.readonly`        | Transformer Property | Is readonly, narrows to `Readonly<Map<T>>` |

### `is.set(valueGuard?)`

Validates a `Set` instance with an optional value guard.

```typescript theme={null}
is.set()(new Set());                         // true
is.set(is.number)(new Set([1, 2, 3]));       // true
is.set(is.string).nonEmpty(new Set(['a']));  // true
is.set(is.number).subsetOf([1, 2, 3, 4])(new Set([1, 2])); // true
```

| Helper                 | Guard Type           | Validates                                  |
| :--------------------- | -------------------- | :----------------------------------------- |
| `.nonEmpty`            | Property             | Size > 0                                   |
| `.empty`               | Property             | Size = 0                                   |
| `.size(num)`           | Factory              | Size = num                                 |
| `.minSize(num)`        | Factory              | Size ≥ num                                 |
| `.maxSize(num)`        | Factory              | Size ≤ num                                 |
| `.has(value)`          | Factory              | Contains value                             |
| `.subsetOf(superset)`  | Factory              | Is subset of iterable superset             |
| `.supersetOf(subset)`  | Factory              | Is superset of iterable subset             |
| `.disjointFrom(other)` | Factory              | Is disjoint from other                     |
| `.readonly`            | Transformer Property | Is readonly, narrows to `Readonly<Set<T>>` |

### `is.promise`

Validates any thenable (has a `.then` method). There are very few use-cases for this.

```typescript theme={null}
is.promise(Promise.resolve(42)); // true
is.promise(42);                  // false
```

### `is.error`

Validates an `Error` instance.

| Helper          | Guard Type | Validates                  |
| --------------- | ---------- | -------------------------- |
| `.message(str)` | Factory    | Error message contains str |
| `.name(str)`    | Factory    | Error name equals str      |
| `.hasCause`     | Property   | Error cause ≠ undefined    |

```typescript theme={null}
is.error(new Error('oops'));                    // true
is.error.message('oops')(new Error('oops'));    // true
is.error.name('TypeError')(new TypeError('bad')); // true
```

### `is.file`

Validates a `File` or `Blob` instance.

| Helper                          | Guard Type | Validates                           |
| ------------------------------- | ---------- | ----------------------------------- |
| `.type(mimeType)`               | Factory    | MIME type matches                   |
| `.extension(ext or ext[])`      | Factory    | Specific file extension(s)          |
| `size(bytes)`                   | Factory    | File size = bytes                   |
| `.minSize(bytes)`               | Factory    | File size ≤ bytes                   |
| `.maxSize(bytes)`               | Factory    | File size ≤ bytes                   |
| `.name(pattern)`                | Factory    | Is File object & filename matches   |
| `.lastModified(date or number)` | Factory    | Is File object & last modified date |

```typescript theme={null}
const imageFile = is.file.type('image/png').maxSize(5 * 1024 * 1024);
imageFile.parse(uploadedFile); // Ok(File) or Err(...)
```

***

## Custom and chas-specific guards

### `is.custom(fn)`

Creates a guard from any predicate function. Use a TypeScript type predicate for full narrowing, or pass a generic type parameter.

```typescript theme={null}
const isOdd = is.custom((n): n is number => typeof n === 'number' && n % 2 !== 0);
isOdd(3); // true
isOdd(2); // false

const isEven = is.custom<number>(n => typeof n === 'number' && n % 2 === 0);
isEven(4); // true
```

### `is.result()`

Guards a `Result<T, E>` value from the `ts-chas` result module.

```typescript theme={null}
import { ok, err } from 'ts-chas/result';

is.result(is.string, is.error); // Guard<Result<string, Error>>
is.result()(ok(42));              // true
is.result(is.number)(ok(42));     // true
is.result().ok(is.number)(ok(42)); // true — narrows to Ok variant
is.result().err(is.string)(err('fail')); // true — narrows to Err variant
```

| Helper              | Guard Type          | Validates                                                                                                  |
| :------------------ | :------------------ | :--------------------------------------------------------------------------------------------------------- |
| `.err(innerGuard?)` | Transformer Factory | Is `Result::Err `and `error` passes innerGuard,<br />narrows to `Result<T, InferGuard<typeof innerGuard>>` |
| `.ok(innerGuard?)`  | Transformer Factory | Is `Result::Ok` and `value` passes innerGuard, narrows to<br />`Result<InferGuard<typeof innerGuard>, E>`  |

### `is.option()`

Guards an `Option<T>` value.

```typescript theme={null}
import { some, none } from 'ts-chas/option';

is.option()(some(42));         // true
is.option(is.number)(some(42)); // true
is.option().some(is.number)(some(42)); // true
is.option().none(none());      // true
```

| Helper               | Guard Type           | Validates                                                                              |
| :------------------- | :------------------- | :------------------------------------------------------------------------------------- |
| `.some(innerGuard?)` | Transformer Factory  | Is `Option::Some` , `value != null` and passes innerGuard,  <br />narrows to `Some<T>` |
| `.none`              | Transformer Property | Is `Option::None`, narrows to `None`                                                   |

### `is.tagged(factory)`

Guards tagged errors created with `defineErrs`.

```typescript theme={null}
import { defineErrs } from 'ts-chas/tagged-errs';

const AppError = defineErrs({
  NotFound: (id: string) => ({ id }),
  Forbidden: (reason: string) => ({ reason }),
});

is.tagged(AppError.NotFound)(error); // narrows to NotFoundErr — typed id available
is.tagged(AppError)(error);          // narrows to NotFoundErr | ForbiddenErr
is.tagged('NotFound')(error);        // structural match on _tag
```
