Typanion

Zero-dependency runtime and static type validator for TypeScript, with type-safe schemas, detailed errors, and value coercion.

Library
npm
v3.14.0
274stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
34/100Needs Attention
Development Activity0
Maintenance0
Community56
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture82
Code Quality78
Innovation75
Learning Curve85

Typanion is a zero-dependency validation library for TypeScript that checks arbitrary, deeply nested data structures at runtime while staying fully aligned with the type system at compile time. Instead of a class-based builder API, its predicates are plain composable functions — t.isString(), t.isObject({...}), t.isArray(t.isNumber()) — that double as TypeScript type predicates, so validating an unknown value with a schema also narrows and infers its static type via InferType.

Beyond pass/fail validation, Typanion can collect detailed per-path error messages and apply in-place coercion so that string inputs (like "true" or an ISO-8601 date string) are converted to their proper runtime types (boolean, Date) as part of validation. This makes it well suited for validating CLI arguments, config files, and API payloads where inputs commonly arrive as strings but should be treated as richer types once validated — Yarn itself uses Typanion for exactly this purpose.

What You Get

  • Composable predicates - isString, isNumber, isObject, isArray, isEnum, isOneOf and more, combined to describe arbitrarily nested shapes.
  • Type inference via InferType - derive a concrete TypeScript type directly from a validator schema instead of maintaining a parallel type definition.
  • Detailed error reporting - pass an errors array to get a list of path-qualified messages describing exactly what failed and where.
  • Built-in coercion - convert validated string input into booleans, numbers, dates, and JSON payloads in place via the coerce option.
  • Zero runtime dependencies - the entire library ships with no third-party packages, keeping it lightweight and tree-shakeable.

Common Use Cases

  • CLI argument validation - validate and coerce string command-line arguments into typed values before use (this is how Yarn’s own CLI is built).
  • Config file validation - check that a parsed JSON/YAML config object matches the expected shape before the app trusts it.
  • API request/response validation - validate untrusted payloads from JSON.parse(request.body) and narrow them to a typed shape with a single call.
  • Type-safe schema-to-type derivation - define a schema once and reuse InferType<typeof schema> everywhere the shape is needed, avoiding duplicate type declarations.

Under The Hood

Architecture The library’s core abstraction is makeValidator (sources/tools.ts), which wraps a test(value, state) function into a branded “Trait” type via makeTrait, giving each predicate a phantom type marker that later powers InferType without any runtime cost. Every exported predicate in sources/predicates/typePredicates.ts, cascadingPredicates.ts, and helperPredicates.ts is a plain function built on this same primitive rather than a class hierarchy, and composite predicates (isArray, isSet, isMap, isTuple, isRecord) are implemented by internally delegating to simpler ones (isSet reuses isArray, isMap reuses isTuple/isRecord). A shared mutable state object (carrying errors, coercion, coercions, and the current path p) is threaded recursively through nested calls, forming one context object that accumulates error messages and staged coercions across an entire validation pass. Because InferType and every predicate’s generic signature depend on the Trait marker produced by makeTrait, changing that one primitive would ripple through the type inference of all exported predicates.

Tech Stack Written in TypeScript (strict mode) with no runtime dependencies at all — only devDependencies are used for the toolchain. It builds via Rollup (@rollup/plugin-typescript) into a lib/ directory that’s swapped in for main at publish time (publishConfig), and package management runs on Yarn 4 (Berry), tracked via .yarnrc.yml and a committed yarn.lock. Its companion documentation site lives in a website/ Yarn workspace and deploys via a dedicated GitHub Pages Actions workflow, separate from the library’s own Node.js CI workflow.

Code Quality Tests live in a single data-driven suite (tests/index.test.ts) that pairs each predicate factory with an array of [input, expectedBoolean] cases and runs them all through one generic Mocha/Chai runner, keeping coverage consistent as new predicates are added. Two further files, type-guards.ts and type-inferences.ts, specifically assert on TypeScript’s inferred types at compile time, and the test script runs a full tsc type-check before the runtime suite — so both behavior and type inference are covered. Error handling is data-oriented rather than exception-based: predicates return a boolean and push messages onto a shared state.errors array via one common helper, reserving thrown exceptions for the explicit assert/assertWithErrors entry points. Naming is consistent (isX predicates, hasX length/shape checks), and CI (GitHub Actions) runs the suite across multiple Node versions on every push; there’s no dedicated linter configuration in the repo.

What Makes It Unique Where comparable runtime validators commonly expose a class-based, method-chaining builder, Typanion’s schemas are ordinary composable functions, which the README calls out explicitly as what keeps the library tree-shakeable despite already being small. Its predicates are also native TypeScript type predicates, so a single validator call both checks a value and narrows/derives its static type via InferType, without a separate type-definition layer to keep in sync. It also folds coercion into the same validator functions used for checking — converting matched strings into booleans, numbers, dates, or parsed JSON payloads in place — rather than requiring a separate transform or pipe step after validation.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search