CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ow

Function argument validation for humans with expressive, chainable API

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

object-array-validation.mddocs/

Object and Array Validation

Advanced validation for objects and arrays including shape validation, property checking, element validation, and structural constraints.

Capabilities

Object Validation

Comprehensive object validation with shape matching, property validation, and instance checking.

/** Object validation predicate */
interface ObjectPredicate extends BasePredicate<object> {
  // Structure validation
  readonly plain: ObjectPredicate;
  readonly empty: ObjectPredicate;
  readonly nonEmpty: ObjectPredicate;
  
  // Property validation
  hasKeys(...keys: string[]): ObjectPredicate;
  hasAnyKeys(...keys: string[]): ObjectPredicate;
  valuesOfType<T>(predicate: BasePredicate<T>): ObjectPredicate;
  deepValuesOfType<T>(predicate: Predicate<T>): ObjectPredicate;
  
  // Shape validation
  partialShape<S>(shape: S): ObjectPredicate;
  exactShape<S>(shape: S): ObjectPredicate;
  deepEqual(expected: object): ObjectPredicate;
  instanceOf(instance: Function): ObjectPredicate;
}

/** Shape definition for object validation */
type Shape = {
  [key: string]: BasePredicate<any> | Shape;
};

Structure Validation Examples:

import ow from 'ow';

// Structure validation
ow({}, ow.object.plain);                    // Plain object, not class instance
ow({}, ow.object.empty);                    // Empty object
ow({ name: 'Alice' }, ow.object.nonEmpty);  // Non-empty object

// Class instance vs plain object
class User { constructor(public name: string) {} }
ow(new User('Alice'), ow.object.instanceOf(User));
ow({ name: 'Alice' }, ow.object.plain);

Property Validation Examples:

import ow from 'ow';

const user = { name: 'Alice', age: 30, address: { city: 'NYC' } };

// Property existence (supports dot-notation)
ow(user, ow.object.hasKeys('name', 'age'));
ow(user, ow.object.hasKeys('address.city'));
ow(user, ow.object.hasAnyKeys('name', 'email'));

// Value type validation
ow({ a: 1, b: 2, c: 3 }, ow.object.valuesOfType(ow.number));
ow(
  { nums: [1, 2], strs: ['a', 'b'] },
  ow.object.deepValuesOfType(ow.any(ow.array, ow.string, ow.number))
);

Shape Validation Examples:

import ow from 'ow';

// Partial shape - ignores extra properties
const userShape = {
  name: ow.string,
  age: ow.number.integer.positive
};

ow({ name: 'Alice', age: 30, extra: 'ignored' }, ow.object.partialShape(userShape));

// Exact shape - fails on extra properties
ow({ name: 'Alice', age: 30 }, ow.object.exactShape(userShape));

// Nested shape validation
const nestedShape = {
  user: {
    name: ow.string,
    contacts: {
      email: ow.optional.string,
      phone: ow.optional.string
    }
  }
};

ow({
  user: {
    name: 'Alice',
    contacts: {
      email: 'alice@example.com'
    }
  }
}, ow.object.exactShape(nestedShape));

// Deep equality
ow({ a: 1, b: [2, 3] }, ow.object.deepEqual({ a: 1, b: [2, 3] }));

Array Validation

Comprehensive array validation with length constraints, element validation, and content checking.

/** Array validation predicate */
interface ArrayPredicate extends BasePredicate<unknown[]> {
  // Length validation
  length(length: number): ArrayPredicate;
  minLength(length: number): ArrayPredicate;
  maxLength(length: number): ArrayPredicate;
  
  // Content validation
  startsWith<T>(searchElement: T): ArrayPredicate;
  endsWith<T>(searchElement: T): ArrayPredicate;
  includes<T>(...searchElements: T[]): ArrayPredicate;
  includesAny<T>(...searchElements: T[]): ArrayPredicate;
  deepEqual<T>(expected: T[]): ArrayPredicate;
  
  // State validation
  readonly empty: ArrayPredicate;
  readonly nonEmpty: ArrayPredicate;
  
  // Type validation
  ofType<U>(predicate: BasePredicate<U>): ArrayPredicate;
  exactShape(predicates: BasePredicate[]): ArrayPredicate;
}

Length Validation Examples:

import ow from 'ow';

// Length constraints
ow([1, 2, 3], ow.array.length(3));
ow([1, 2], ow.array.minLength(2));
ow([1, 2, 3], ow.array.maxLength(5));
ow([], ow.array.empty);
ow([1], ow.array.nonEmpty);

Content Validation Examples:

import ow from 'ow';

const numbers = [1, 2, 3, 4, 5];

// Element position validation
ow(numbers, ow.array.startsWith(1));
ow(numbers, ow.array.endsWith(5));

// Content inclusion
ow(numbers, ow.array.includes(2, 3, 4));
ow(numbers, ow.array.includesAny(2, 10, 20));

// Deep equality
ow([[1, 2], [3, 4]], ow.array.deepEqual([[1, 2], [3, 4]]));

Type Validation Examples:

import ow from 'ow';

// All elements must match predicate
ow([1, 2, 3], ow.array.ofType(ow.number.positive));
ow(['a', 'b', 'c'], ow.array.ofType(ow.string.nonEmpty));

// Mixed type arrays
ow([1, 'hello', true], ow.array.ofType(ow.any(ow.number, ow.string, ow.boolean)));

// Exact shape validation - elements match predicates at same indices
ow(['Alice', 30, true], ow.array.exactShape([
  ow.string,
  ow.number.integer.positive,
  ow.boolean
]));

// Array of objects
const users = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 }
];

ow(users, ow.array.ofType(ow.object.exactShape({
  name: ow.string,
  age: ow.number.integer.positive
})));

Advanced Usage Examples

Nested Object and Array Validation

import ow from 'ow';

// Complex nested structure
const apiResponse = {
  users: [
    {
      id: 1,
      profile: {
        name: 'Alice',
        contacts: ['alice@example.com', '+1-555-0123']
      },
      permissions: ['read', 'write']
    }
  ],
  meta: {
    total: 1,
    page: 1
  }
};

const responseShape = {
  users: ow.array.ofType(ow.object.exactShape({
    id: ow.number.integer.positive,
    profile: ow.object.exactShape({
      name: ow.string.nonEmpty,
      contacts: ow.array.ofType(ow.string.nonEmpty)
    }),
    permissions: ow.array.ofType(ow.string.oneOf(['read', 'write', 'admin']))
  })),
  meta: ow.object.exactShape({
    total: ow.number.integer.positive,
    page: ow.number.integer.positive
  })
};

ow(apiResponse, ow.object.exactShape(responseShape));

Dynamic Object Validation

import ow from 'ow';

// Validate object with dynamic keys
const dynamicObject = {
  'user:1': { name: 'Alice', active: true },
  'user:2': { name: 'Bob', active: false }
};

// All keys must match pattern, all values must match shape
ow(Object.keys(dynamicObject), ow.array.ofType(ow.string.matches(/^user:\d+$/)));
ow(dynamicObject, ow.object.valuesOfType(ow.object.exactShape({
  name: ow.string,
  active: ow.boolean
})));

Array Transformation Validation

import ow from 'ow';

// Validate transformed arrays
const input = ['1', '2', '3'];
const numbers = input.map(Number);

ow(input, ow.array.ofType(ow.string.numeric));
ow(numbers, ow.array.ofType(ow.number.integer));

Install with Tessl CLI

npx tessl i tessl/npm-ow

docs

advanced-features.md

builtin-types.md

collection-types.md

index.md

object-array-validation.md

primitive-types.md

typed-arrays.md

tile.json