Typescript fast & easy asserts
npm install assertrouteTiny, fast runtime assertions with clean TypeScript narrowing — plus a block-scoped “route” wrapper that converts assertion failures into safe default returns.
Validate at the top; write clear, assumption-friendly logic in the middle. If any assert* throws an AssertError inside the route, we stop and return your default. Fewer try/catch, fewer defensive if checks, better narrowing.
Have you always disliked counting the brackets of your nested conditions? There has got to be a better way!
See also: CHEATSHEET.md for advanced patterns and quick references.
``bash`
npm i assertroute
`ts
import { v } from 'assertroute';
const findClientTags = v.fn
v.assertObject(cdata);
v.assertArray(allclients);
v.assertArray(cdata.tags, 'Expected tags array');
v.assertArrayNotEmpty(cdata.tags, 'Tags must not be empty');
const tags = cdata.tags as string[];
v.assertArrayOnlyHasStrings(tags, 'Tags must be strings');
// From here, TypeScript trusts the narrowing;
// logic reads clearly with fewer conditionals.
return allclients.filter((x) => Array.isArray(x.tagsShared) && x.tagsShared.some((t) => tags.includes(t))).map((x) => x.name);
});
`
Key benefits:
- Strong narrowing: thrown AssertError prunes invalid paths, so TS treats code after asserts as safe.assert*
- Declarative checks: catalog of strict helpers replaces scattered if guards.
- Localized failure handling: one default return per route instead of many ad-hoc catch/fallbacks.
---
- dist/assertroute.esm.js – ESM build for modern bundlers/Node ESM (import).
- dist/assertroute.cjs – CommonJS build for Node (require).
- dist/assertroute.browser.min.js – IIFE build for browsers (window.assertroute = { … }).
- \*.map – Source maps for debugging.
- assertroute.d.ts (+ .d.ts.map) – TypeScript typings (includes JSDoc).
> package.json uses "exports" and "type": "module". Tree-shaking friendly ("sideEffects": false).
Plain function function toUpper(x: unknown) { assertString(x); return x.toUpperCase(); // x is string }
`ts`
const value = v.route(0, () => {
v.assertNumber(Math.random());
return 42;
}); // 42 or 0 on if assert failed with AssertError
`ts`
const get = v.async(null, async () => {
const r = await fetch('/data');
v.assert(r.ok);
return await r.json();
}); // Promise
`ts`
import { v } from 'assertroute';
const isValidUser = v.confirmOne(() => {
v.assertObject({ name: 'Luuk' });
v.assertString('Luuk');
});
// true when single assertion passes
> All are function declarations (narrowing-safe). Names are stable; params are obvious from the name—see editor tooltips or the d.ts.
- assertRoute, assertRouteAsync, routeWith, isValid
- assert, AssertError
- assertString, assertNumber, assertBoolean, assertArray, assertObject, assertDate, assertFunction
- assertPromiseLike, assertDefined, assertNonNull, assertPresent, assertInstanceOf
- expectString, expectNumber, expectBoolean, expectArray, expectObject, expectDate
- assertNonEmptyString
- assertStringLength, assertStringLengthAtLeast, assertStringLengthAtMost, assertStringLengthBetween
- assertStringContains, assertStringStartsWith, assertStringEndsWith, assertStringMatches
- assertStringEqualsIgnoreCase
- assertStringIncludesAny, assertStringIncludesAll
- assertStringIsJSON, assertStringTrimmedNotEmpty
- assertStringEqualsCanonical, assertStringContainsCanonical
- assertNumberGreaterThan, assertNumberGreaterOrEqual
- assertNumberLessThan, assertNumberLessOrEqual
- assertNumberBetween
- assertNumberNotZero, assertNumberPositive, assertNumberNonNegative
- assertNumberNegative, assertNumberNonPositive
- assertNumberInteger, assertNumberSafeInteger
- assertNumberApproxEquals
- Aliases: assertIsNotZero, assertIsPositive, assertIsNegative
- assertArrayNotEmpty, assertArrayLength
- assertArrayHasAnyOf, assertArrayHasEveryOf
- assertArrayItemIsBoolean, assertArrayItemIsString, assertArrayItemIsNumber, assertArrayItemIsObject
- assertArrayIncludesString, assertArrayIncludesNumber, assertArrayIncludesObject
- assertArrayOnlyHasObjects, assertArrayOnlyHasStrings, assertArrayOnlyHasNumbers
- assertArrayEveryIsFalsy, assertArrayEveryIsTruthy
- assertArrayIncludesCondition
- assertArrayUnique
- Alias: assertIsArrayNotEmpty
- Consistency (your addition): arrayIsConsistent _(or assertArrayConsistent\* if you used that naming)_
- assertHasKey, assertHasKeys, assertKeyEquals, assertSameKeys
- assertAllKeysFalsy, assertAllKeysSet, assertAnyKeyNull
- assertNonEmptyRecord, assertSubset, assertHasPath
- assertMapHasKey, assertSetHasValue
- assertDateEarlier, assertDateLater, assertDateBetween, assertDateYear
- assertTrue, assertFalse, assertNull, assertUndefined
- assertEquals, assertNotEquals, assertDeepEquals
- assertMatchesSchema, assertOneOfPrimitive
- assertElement, assertElementHasChildren, assertElementHasChild
- assertElementHasChildMatching, assertElementHasDescendant
- assertElementHasAttribute, assertElementAttributeEquals
- assertElementHidden, assertElementVisible
- assertPlainObject, assertNoExtraKeys
- assertArrayOf, assertRecordOf, assertArrayUnique, assertArraySortedNumber
- assertInstanceOfAny, assertURLString, assertUUID, assertEmail
- assertNonEmptyMap, assertNonEmptySet
- assertDeepSubset, assertDiscriminant, assertWithinSet
- assertNever _(exhaustiveness)_
- TypeScript: all functions are declared (not const) to avoid TS2775; narrowing works reliably.
- Errors: assertions throw AssertError (not plain Error).
- Tree-shaking: builds are side-effect free. Import only what you use.
- Browser global: IIFE exposes window.assertroute with the full API.
Pro tip: keep one canonical name per helper. It improves discoverability, docs, and IntelliSense — no alias sprawl.
Happy asserting.
- Fn: returns a wrapper function. Use when you want a reusable function that catches AssertError inside and returns a fallback. It never auto-executes.fn
- Route: auto-executes when the callback has zero parameters; otherwise returns a wrapper. Use for concise “compute now or fall back” patterns.
- With args: both return a wrapper — equivalent behavior. Prefer by default; use route only if you need its options.AssertError
- Error handling: both catch . route/routeAsync also accept { catchNonAssertErrors?: boolean, onError?: (err: AssertError) => void }.
Examples
`ts
import * as v from 'assertroute';
// 1) Replace a function with a safe wrapper (fn)
export const getNonCheckedScenes = v.fn
const rows = db.prepare('SELECT scene_id FROM scenes WHERE checkedForStamps = 0').all() as unknown[];
const results = v.expectArrayNotEmpty(rows);
v.assertObjectArrayEveryHasKeys(results, 'scene_id');
return results.map((r) => (r as Record
});
// 2) Compute immediately with auto-execute (route) — zero-arg callback runs now
export const bootScenes: string[] = v.route([], () => {
const rows = db.prepare('SELECT scene_id FROM scenes WHERE boot = 1').all() as unknown[];
const results = v.expectArray(rows);
v.assertObjectArrayEveryHasKeys(results, 'scene_id');
return results.map((r) => (r as Record
});
// 3) With args, route returns a wrapper
export const scenesForProject = v.route
v.assertStringTrimmedNotEmpty(projectId);
const rows = db.prepare('SELECT scene_id FROM scenes WHERE project_id = ?').all(projectId) as unknown[];
const results = v.expectArray(rows);
v.assertObjectArrayEveryHasKeys(results, 'scene_id');
return results.map((r) => (r as Record
});
// 4) Async variant
export const fetchJson = v.routeAsync
`
``