Violations fire at their origin, not three layers later. Every assertion always throws — no configuration, no silent modes, no surprises.
Richly formatted errors
ELM-inspired output with diffs, labels, and notes. ANSI colours on TTY, plain text in pipes and CI, collapsible groups in browser DevTools. Respects NO_COLOR.
Chainable API
check(value).noNils().uniqueBy("id").all(u => u.active) — fluent, readable, type-safe. Declare all invariants on a value in one place.
Zero setup
Import and use — no configuration files, no entry-point calls, no mode system. Assertions always throw on failure, in every environment.
TypeScript types vanish at runtime. Assertions don't.
Static types are a compile-time promise. At runtime, that promise is gone. Every null you thought was impossible, every shape you assumed was enforced — they all arrive anyway. The standard response is defensive code: if (!x) return. Silent. Invisible. The bug propagates.
AssertCheck replaces that with a contract system: declare what must never happen, fire exactly where it happens, and surface exactly what went wrong.
ts
function chargeOrder(order: Order) { if (!order) return // absorbed — caller gets undefined, no trace if (!order.amount) return // absorbed — negative amounts silently pass if (order.status !== "pending") return // absorbed — double-charge possible // Three broken assumptions. None of them surfaced. Ever.}
ts
function chargeOrder(order: Order) { assert.notNil(order, "order is required") assert.positive(order.amount, "order amount must be positive") assert.equal(order.status, "pending", { msg: "order must be pending before charge", actual: "order.status", note: "call resetOrder() before retrying", }) // Every precondition is named, enforced, and traceable.}
When order.status is "paid" instead of "pending", you get a formatted diagnostic — not a cryptic stack trace.
══════════════════ ● order must be pending before charge ══════── values ────────────────────────────────────────────────────── + expected "pending" ✗ order.status "paid"── note ──────────────────────────────────────────────────────── call resetOrder() before retrying════════════════════════════════════════════════════════════════
Exact location. Exact values. Exact next step. No debugger, no guessing, no context-switching.
Deep equality failures go further — a field-by-field structural diff:
══════════════════ ● User shape mismatch ══════════════════════── diff ──────────────────────────────────────────────────────── · id "usr_123" ~ status expected "active" actual "banned" + role "admin" ← missing in actual════════════════════════════════════════════════════════════════
Output adapts automatically: ANSI on TTY, plain text in CI, console.groupCollapsed in the browser.
Zod and Yup are schema validators — they validate data that comes in from the outside (forms, APIs, JSON). AssertCheck is a contract system — it enforces invariants at every internal boundary: function arguments, state transitions, external responses, collection shapes. The two are complementary, not competing.
Every assertion accepts an optional opts parameter with a message, an actual-value label, and a hint for the developer.
ts
import { assert, check } from "assertcheck"// Existence & type guardsassert.notNil(user, "user is required")assert.string(userId, "userId must be a string")assert.positive(price, "price must be positive")// Deep equality with structural diffassert.deepEqual(result, expected, "API response shape changed")// Chainable invariants on collectionscheck(orders) .notEmpty("cart must not be empty before checkout") .noNils("no null order items allowed") .all(o => o.amount > 0, "all orders must have a positive amount") .uniqueBy("id", "duplicate order IDs detected")// Object shape guardscheck(config) .hasKeys(["host", "port", "database"], "missing required config keys") .dig("database.pool.max", 10, "pool size must be at least 10")
50+ methods covering existence, types, numerics, equality, arrays, objects, and function purity.
AssertCheck is maintained by Vagabond Studio — a fully remote, senior-only collective of engineers and designers.
We build TypeScript, Vue.js, Rails, and Django products from greenfield to production. AssertCheck is how we guard every internal boundary in every service we ship.