Skip to main content
A Guard<T> is a TypeScript type predicate; a function (value: unknown) => value is T — with chainable helpers for common validations, schema parsing, and transformation. Unlike most validators, guards work as plain if conditions, so narrowing is free.

The is namespace

All built-in guards live on the is object:

Chaining helpers

Under the hood, ts-chas chains evaluations from left to right. When you use the guard as a boolean type predicate:
Here is exactly what happens during the if check:
  1. It validates that value is a string (from is.string).
  2. It applies the .trim() inline to a temporary, internal value.
  3. It passes that temporary, trimmed string into the .email(...) validation rule.
If all three steps succeed, the predicate returns true, and TypeScript safely narrows value to a string. It’s important to remember that because TypeScript type predicates (v is string) cannot mutate variables, the value inside the if block is still the original, _un-trimmed _string you started with. It’s simply _guaranteed _to be an email once you trim it! If you want the actual trimmed string value to work with, you map it through .parse(...) or .assert(...) instead of using it as a raw boolean check:

Universal helpers

Every guard, regardless of type, has these methods:

.parse(value)Result<T, GuardErr>

The primary way to validate data and get a typed result:

.error(message) — custom error messages

.nullable(), .optional(), .nullish()

.and(), .or()

.where(predicate) — arbitrary refinement

.brand(tag) — branded types

Object guards

Array guards

The .array property also works as a shorthand on any guard:

Schema parsing

Use defineSchemas to define reusable schemas that collect all validation errors instead of short-circuiting on the first:

InferSchema — type inference

.parse(data)Result<T, GuardErr[]>

.assert(data) — throw on failure

Standard Schema v1 compatibility

All guards implement the Standard Schema v1 spec via the ~standard property. This means you can drop them directly into tRPC, react-hook-form, Drizzle, and other compatible ecosystems with no adapter needed:

Namespace extensions

Add your own guards to the is namespace with is.extend(). Extensions are typed and chainable:
Store the extended myIs instance as your project’s canonical import. This lets you share custom guards across your codebase without re-extending everywhere.

Hashing with is.string.hash()

The is.string.hash() helper uses @noble/hashes under the hood, which runs isomorphically in Node.js, browsers, and edge runtimes with no native bindings required:
Supported algorithms: sha1, sha256, sha384, sha512, md5. Supported encodings: hex, base64, base64url.