Skip to main content

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.

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.
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.
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.
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.
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.
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.
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.
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.
const Base  = is.object({ id: is.number });
const Named = Base.extend({ name: is.string });
Named({ id: 1, name: 'Alice' }); // true

Other object helpers

HelperGuard TypeValidates
.size(n)FactorySize = n
.minSize(n)FactorySize ≥ n
.maxSize(n)FactorySize ≤ n
.has(key, guard?)Transformer FactoryObject has property that (optionally) satisfies
guard
.hasAll(keys)FactoryObject has all specified keys
.hasOnly(keys)FactoryObject 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.
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

HelperGuard TypeValidates
.min(n)FactoryLength ≥ n
.max(n)FactoryLength ≤ n
.length(n)FactoryLength = n
.nonEmptyPropertyLength ≥ 1
.uniquePropertyEvery element is unique
.includes(item)FactoryArray contains item
.excludes(item)FactoryArray does not contain item
.readonlyTransformer PropertyWraps array in Object.freeze(), returns readonly
array when parsed
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.
// 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.tuple([...], restGuard?)

Validates a fixed-length array where each position has its own guard. Pass a second argument to allow variadic trailing elements.
// 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
HelperGuard TypeValidates
.nonEmptyPropertyTuple is not empty
.uniquePropertyAll elements are unique
.min(n)FactoryLength ≥ n
.max(n)FactoryLength ≤ n
.size(n)FactoryLength = n
.includes(item)FactoryTuple has item
.excludes(item)FactoryTuple does not have item
.readonlyTransformer PropertyTuples are already readonly, included
for consistency

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

is.union(...guards) — passes if the value satisfies at least one guard.
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.
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.
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.
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)
HelperGuard TypeValidates
.before(date)FactoryDate is before the given date
.after(date)FactoryDate is after the given date
.between(min, max)FactoryDate is between min and max
.weekendPropertyDate is a weekend
.weekdayPropertyDate is a weekday
.day(dow)FactoryDate is given day of the week
.month(num)FactoryDate has given month (0-indexed)
.year(num)FactoryDate has given year
.dayOfMonth(num)FactoryDate is a specific day of the month (1-31)
.timezoneOffset(minutes)FactoryDate has given timezone offset
.hour(num)FactoryDate has specific hour
.minute(num)FactoryDate has specific minute
.second(num)FactoryDate has specific second
.millisecond(num)FactoryDate has specific millisecond
.sameDayAs(date)FactoryDate is on the same calendar day as given date
.sameMonthAs(date)FactoryDate is in the same month as given date
.sameYearAs(date)FactoryDate is in the same year as given date
.futurePropertyDate is in the future
.pastPropertyDate is in the past
.todayPropertyDate is today
.tomorrowPropertyDate is tomorrow
.yesterdayPropertyDate is yesterday
.startOf(unit)Transformer FactoryTruncates to start of 'year', 'month', 'day', etc.
.endOf(unit)Transformer FactorySame as .startOf but for end of unit

is.regexp

Validates a RegExp instance. Optionally validates against a specific pattern.
is.regexp(/hello/); // true
is.regexp('hello'); // false

const specific = is.regexp(/^[a-z]+$/);
specific.parse(/^[a-z]+$/); // Ok(RegExp)
HelperGuard TypeValidates
.globalPropertyHas a g flag
.ignoreCasePropertyHas i flag
.multilinePropertyHas m flag
.unicodePropertyHas u flag
.stickyPropertyHas y flag
.dotAllPropertyHas s flag
.source(pattern)FactoryPattern matches source
.test(string)FactoryString passes value.test()
.flags(string)FactoryHas exactly the specified flags

is.url

Validates a URL instance (not a string — use is.string.url for strings).
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/')
HelperGuard TypeValidates
.httpTransformer PropertyProtocol is http or https
.httpsTransformer PropertyProtocol is strictly https
.secureTransformer PropertySame as .https
.localTransformer PropertyMatches localhost, 127.0.0.1, ::1
.hasSearchTransformer PropertyHas a search query string
.hasHashTransformer PropertyHas a hash fragment
.protocol(pattern)FactoryPattern matches protocol WITHOUT
trailing colon
.hostname(pattern)FactoryPattern matches hostname
.pathname(pattern)FactoryPattern matches pathname
.port(n?)FactoryPort = n or is present

is.map(keyGuard?, valueGuard?)

Validates a Map instance with optional key and value guards.
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
HelperGuard TypeValidates
.nonEmptyPropertySize > 0
.emptyPropertySize = 0
.size(num)FactorySize = num
.minSize(num)FactorySize ≥ num
.maxSize(num)FactorySize ≤ num
.hasKey(key)FactoryContains key
.hasValue(value)FactoryContains value
.readonlyTransformer PropertyIs readonly, narrows to Readonly<Map<T>>

is.set(valueGuard?)

Validates a Set instance with an optional value guard.
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
HelperGuard TypeValidates
.nonEmptyPropertySize > 0
.emptyPropertySize = 0
.size(num)FactorySize = num
.minSize(num)FactorySize ≥ num
.maxSize(num)FactorySize ≤ num
.has(value)FactoryContains value
.subsetOf(superset)FactoryIs subset of iterable superset
.supersetOf(subset)FactoryIs superset of iterable subset
.disjointFrom(other)FactoryIs disjoint from other
.readonlyTransformer PropertyIs readonly, narrows to Readonly<Set<T>>

is.promise

Validates any thenable (has a .then method). There are very few use-cases for this.
is.promise(Promise.resolve(42)); // true
is.promise(42);                  // false

is.error

Validates an Error instance.
HelperGuard TypeValidates
.message(str)FactoryError message contains str
.name(str)FactoryError name equals str
.hasCausePropertyError cause ≠ undefined
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.
HelperGuard TypeValidates
.type(mimeType)FactoryMIME type matches
.extension(ext or ext[])FactorySpecific file extension(s)
size(bytes)FactoryFile size = bytes
.minSize(bytes)FactoryFile size ≤ bytes
.maxSize(bytes)FactoryFile size ≤ bytes
.name(pattern)FactoryIs File object & filename matches
.lastModified(date or number)FactoryIs File object & last modified date
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.
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.
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
HelperGuard TypeValidates
.err(innerGuard?)Transformer FactoryIs Result::Err and error passes innerGuard,
narrows to Result<T, InferGuard<typeof innerGuard>>
.ok(innerGuard?)Transformer FactoryIs Result::Ok and value passes innerGuard, narrows to
Result<InferGuard<typeof innerGuard>, E>

is.option()

Guards an Option<T> value.
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
HelperGuard TypeValidates
.some(innerGuard?)Transformer FactoryIs Option::Some , value != null and passes innerGuard,
narrows to Some<T>
.noneTransformer PropertyIs Option::None, narrows to None

is.tagged(factory)

Guards tagged errors created with defineErrs.
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