Typanion

3.14.0 · active · verified Sun Apr 19

Typanion is a lean, type-safe runtime TypeScript validator library with zero external runtime dependencies. It excels at validating complex, nested data structures and provides strong type inference, which allows TypeScript to refine types based on successful validation. Unlike some alternatives, Typanion emphasizes a functional and tree-shakeable API, making it efficient for bundlers. It provides detailed error reports and supports coercions, enabling data transformation during validation. While it may not have the extensive ecosystem of libraries like Zod or Yup, its core differentiators lie in its minimal footprint, functional design, and robust TypeScript inference. Currently, in version 3.14.0, its release cadence appears less frequent, suggesting a focus on stability over rapid iteration, with the last major activity around two years ago.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to define a schema for a user object, validate both valid and invalid data, collect detailed error messages, leverage TypeScript's type inference upon successful validation, and briefly showcases a coercion example.

import * as t from 'typanion';

// Define a schema for a user object
const isUser = t.isObject({
  id: t.isNumber(),
  name: t.isString(),
  email: t.isOptional(t.isString()),
  age: t.cascade(t.isNumber(), [t.isInteger(), t.isInInclusiveRange(0, 120)]),
  roles: t.isArray(t.isString(), { maxLength: 3 }),
  isActive: t.isBoolean(),
});

// Example valid data
const validUserData = {
  id: 123,
  name: 'Alice',
  email: 'alice@example.com',
  age: 30,
  roles: ['admin', 'editor'],
  isActive: true,
};

// Example invalid data
const invalidUserData = {
  id: 'abc', // Should be number
  name: 123,  // Should be string
  age: 150,   // Out of range
  roles: ['guest', 'viewer', 'reporter', 'qa'], // Too many roles
  unknownProp: 'oops' // Extraneous property (fails by default)
};

interface User {
  id: number;
  name: string;
  email?: string;
  age: number;
  roles: string[];
  isActive: boolean;
}

// Validate valid data
const errorsForValid: string[] = [];
if (isUser(validUserData, { errors: errorsForValid })) {
  console.log('Valid user data:', validUserData);
  // TypeScript knows validUserData is now of type User
  const user: User = validUserData;
  console.log(user.name);
} else {
  console.error('Validation failed for valid data:', errorsForValid);
}

console.log('\n--- Attempting to validate invalid data ---');

// Validate invalid data
const errorsForInvalid: string[] = [];
if (isUser(invalidUserData, { errors: errorsForInvalid })) {
  console.log('Invalid user data (unexpected success):', invalidUserData);
} else {
  console.error('Validation failed for invalid data:');
  errorsForInvalid.forEach(error => console.error(`- ${error}`));
  // TypeScript still considers invalidUserData as 'unknown' here
  // because validation failed.
}

// Example with coercion (though not typical for this schema)
const isCoercibleNumber = t.applyCoercion(t.isNumber(), t.isString());
const coercions: t.Coercion[] = [];
const potentiallyNumber = '42';

if (isCoercibleNumber(potentiallyNumber, { coercions })) {
    for (const [p, op] of coercions) op();
    console.log('\nCoerced value:', potentiallyNumber); // will be 42 (number)
    const num: number = potentiallyNumber;
    console.log(typeof num); // 'number'
} else {
    console.error('Coercion failed');
}

view raw JSON →