CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sindresorhus--is

Type check values with comprehensive TypeScript type guards and runtime assertions

Pending
Overview
Eval results
Files

validation.mddocs/

Validation and Logic

Multi-value validation, logical operations, and specialized validation patterns including predicate testing, enum checking, and truthiness validation.

Capabilities

Multi-value Validation

Check multiple values against predicates for comprehensive validation.

/**
 * Check if all values pass the predicate
 * @param predicate - Function to test each value
 * @param values - Values to test
 * @returns True if all values pass predicate
 */
function isAll(predicate: Predicate, ...values: unknown[]): boolean;

/**
 * Check if any value passes any of the predicates
 * @param predicate - Single predicate or array of predicates
 * @param values - Values to test
 * @returns True if any value passes any predicate
 */
function isAny(predicate: Predicate | Predicate[], ...values: unknown[]): boolean;

type Predicate = (value: unknown) => boolean;

Usage Examples:

import is from '@sindresorhus/is';

// Test all values against single predicate
is.all(is.string, 'hello', 'world', 'test'); // => true
is.all(is.string, 'hello', 42, 'test'); // => false
is.all(is.number, 1, 2, 3, 4); // => true

// Test any value against single predicate
is.any(is.string, 42, true, 'hello'); // => true
is.any(is.string, 42, true, null); // => false

// Test any value against multiple predicates
is.any([is.string, is.number], {}, true, 'hello'); // => true (string matches)
is.any([is.boolean, is.number], 'hello', [], {}); // => false

// Practical usage
function validateUserData(name: unknown, age: unknown, email: unknown) {
  if (!is.all(is.string, name, email)) {
    throw new Error('Name and email must be strings');
  }
  
  if (!is.number(age)) {
    throw new Error('Age must be a number');
  }
  
  return { name, age, email };
}

// Flexible validation
function hasValidId(data: unknown[]) {
  // Accept either string or number IDs
  return is.any([is.string, is.number], ...data);
}

Truthiness and Falsiness

Check logical truthiness and falsiness of values.

/**
 * Check if value is truthy
 * @param value - Value to check
 * @returns True if value is truthy
 */
function isTruthy<T>(value: T | Falsy): value is T;

/**
 * Check if value is falsy
 * @param value - Value to check
 * @returns True if value is falsy
 */
function isFalsy(value: unknown): value is Falsy;

type Falsy = false | 0 | 0n | '' | null | undefined;

Usage Examples:

import is from '@sindresorhus/is';

// Truthy values
is.truthy('hello'); // => true
is.truthy(42); // => true
is.truthy([]); // => true (arrays are truthy)
is.truthy({}); // => true (objects are truthy)

// Falsy values
is.falsy(false); // => true
is.falsy(0); // => true
is.falsy(0n); // => true
is.falsy(''); // => true
is.falsy(null); // => true
is.falsy(undefined); // => true

is.falsy('0'); // => false (string '0' is truthy)
is.falsy([]); // => false (empty array is truthy)

// Type guard usage
function processValue<T>(value: T | null | undefined) {
  if (is.truthy(value)) {
    // value is now typed as T (non-falsy)
    return value.toString();
  }
  return 'No value provided';
}

// Filtering arrays
const mixedArray = ['hello', '', 0, 'world', null, 42, false];
const truthyValues = mixedArray.filter(is.truthy);
console.log(truthyValues); // ['hello', 'world', 42]

const falsyValues = mixedArray.filter(is.falsy);
console.log(falsyValues); // ['', 0, null, false]

Enum Case Validation

Check if a value is a member of a TypeScript enum.

/**
 * Check if value is a member of the given enum
 * @param value - Value to check
 * @param targetEnum - Enum to check against
 * @returns True if value is enum member
 */
function isEnumCase<T = unknown>(value: unknown, targetEnum: T): value is T[keyof T];

Usage Examples:

import is from '@sindresorhus/is';

enum Direction {
  Up = 'up',
  Down = 'down',
  Left = 'left',
  Right = 'right'
}

enum Status {
  Pending = 0,
  Approved = 1,
  Rejected = 2
}

is.enumCase('up', Direction); // => true
is.enumCase('diagonal', Direction); // => false
is.enumCase(1, Status); // => true
is.enumCase(3, Status); // => false

// Type guard usage
function processDirection(input: unknown) {
  if (is.enumCase(input, Direction)) {
    // input is now typed as Direction
    switch (input) {
      case Direction.Up:
        return 'Moving up';
      case Direction.Down:
        return 'Moving down';
      case Direction.Left:
        return 'Moving left';
      case Direction.Right:
        return 'Moving right';
    }
  }
  throw new Error('Invalid direction');
}

// API response validation
function validateStatus(response: { status: unknown }) {
  if (is.enumCase(response.status, Status)) {
    return response.status; // Typed as Status
  }
  throw new Error('Invalid status in response');
}

Direct Instance Checking

Check if an instance is a direct instance of a class (not inherited).

/**
 * Check if instance is direct instance of class (not inherited)
 * @param instance - Instance to check
 * @param class_ - Class constructor to check against
 * @returns True if instance is direct instance
 */
function isDirectInstanceOf<T>(instance: unknown, class_: Class<T>): instance is T;

type Class<T, Arguments extends unknown[] = any[]> = Constructor<T, Arguments> & {prototype: T};

Usage Examples:

import is from '@sindresorhus/is';

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  breed: string;
  constructor(name: string, breed: string) {
    super(name);
    this.breed = breed;
  }
}

const animal = new Animal('Generic');
const dog = new Dog('Buddy', 'Golden Retriever');

// Direct instance checking
is.directInstanceOf(animal, Animal); // => true
is.directInstanceOf(dog, Animal); // => false (inherited, not direct)
is.directInstanceOf(dog, Dog); // => true

// Compare with regular instanceof
console.log(dog instanceof Animal); // => true (inheritance chain)
console.log(is.directInstanceOf(dog, Animal)); // => false (direct only)

// Type guard usage
function processAnimal(animal: unknown) {
  if (is.directInstanceOf(animal, Animal)) {
    // animal is typed as Animal (not subclass)
    console.log('Processing base animal:', animal.name);
  } else if (is.directInstanceOf(animal, Dog)) {
    // animal is typed as Dog
    console.log('Processing dog:', animal.name, animal.breed);
  }
}

Property Key Validation

Check if a value can be used as an object property key.

/**
 * Check if value can be used as object property key
 * @param value - Value to check
 * @returns True if value is valid property key
 */
function isPropertyKey(value: unknown): value is PropertyKey;

type PropertyKey = string | number | symbol;

Usage Examples:

import is from '@sindresorhus/is';

is.propertyKey('key'); // => true
is.propertyKey(42); // => true
is.propertyKey(Symbol('key')); // => true

is.propertyKey({}); // => false
is.propertyKey(null); // => false
is.propertyKey(true); // => false

// Type guard usage
function safeObjectAccess(obj: Record<PropertyKey, unknown>, key: unknown) {
  if (is.propertyKey(key)) {
    // key is now typed as PropertyKey
    return obj[key];
  }
  throw new Error('Invalid property key');
}

// Dynamic property setting
function setProperty(obj: object, key: unknown, value: unknown) {
  if (is.propertyKey(key)) {
    (obj as any)[key] = value;
    return true;
  }
  return false;
}

// Object key filtering
function filterValidKeys(keys: unknown[]): PropertyKey[] {
  return keys.filter(is.propertyKey);
}

Usage Patterns

Batch Validation

import is from '@sindresorhus/is';

function validateBatch<T>(
  values: unknown[], 
  predicate: (value: unknown) => value is T
): T[] {
  if (!is.all(predicate, ...values)) {
    throw new Error('All values must pass validation');
  }
  return values as T[];
}

// Usage
const stringArray = validateBatch(['a', 'b', 'c'], is.string);
const numberArray = validateBatch([1, 2, 3], is.number);

function validateMixedTypes(values: unknown[]) {
  const hasStrings = is.any(is.string, ...values);
  const hasNumbers = is.any(is.number, ...values);
  
  return {
    hasStrings,
    hasNumbers,
    isHomogeneous: is.all(is.string, ...values) || is.all(is.number, ...values)
  };
}

Configuration Validation

import is from '@sindresorhus/is';

enum LogLevel {
  Debug = 'debug',
  Info = 'info',
  Warn = 'warn',
  Error = 'error'
}

interface Config {
  host: string;
  port: number;
  logLevel: LogLevel;
  features: string[];
}

function validateConfig(config: Record<string, unknown>): Config {
  // Required string fields
  if (!is.all(is.string, config.host)) {
    throw new Error('Host must be a string');
  }
  
  // Port validation
  if (!is.number(config.port) || config.port <= 0) {
    throw new Error('Port must be a positive number');
  }
  
  // Enum validation
  if (!is.enumCase(config.logLevel, LogLevel)) {
    throw new Error('Invalid log level');
  }
  
  // Array validation
  if (!is.array(config.features, is.string)) {
    throw new Error('Features must be array of strings');
  }
  
  return config as Config;
}

Type-safe Filtering

import is from '@sindresorhus/is';

function partitionArray<T>(
  array: unknown[], 
  predicate: (value: unknown) => value is T
): [T[], unknown[]] {
  const matching: T[] = [];
  const nonMatching: unknown[] = [];
  
  for (const item of array) {
    if (predicate(item)) {
      matching.push(item);
    } else {
      nonMatching.push(item);
    }
  }
  
  return [matching, nonMatching];
}

// Usage
const mixedData = ['hello', 42, true, 'world', null, 3.14];
const [strings, nonStrings] = partitionArray(mixedData, is.string);
const [numbers, nonNumbers] = partitionArray(nonStrings, is.number);

console.log('Strings:', strings); // ['hello', 'world']
console.log('Numbers:', numbers); // [42, 3.14]

Flexible Type Checking

import is from '@sindresorhus/is';

function acceptMultipleTypes(value: unknown): string {
  if (is.any([is.string, is.number, is.boolean], value)) {
    return String(value);
  }
  
  if (is.any([is.array, is.plainObject], value)) {
    return JSON.stringify(value);
  }
  
  return 'Unknown type';
}

function requireAllFields(data: Record<string, unknown>, ...fields: string[]) {
  const values = fields.map(field => data[field]);
  
  if (!is.all(is.truthy, ...values)) {
    throw new Error(`Missing required fields: ${fields.join(', ')}`);
  }
  
  return data;
}

Notes

  • isAll() requires all values to pass the predicate; fails fast on first failure
  • isAny() with single predicate tests if any value passes; with array tests if any value passes any predicate
  • isTruthy() and isFalsy() follow JavaScript truthiness rules exactly
  • isEnumCase() works with both string and numeric enums
  • isDirectInstanceOf() checks prototype chain directly, not inheritance
  • isPropertyKey() validates JavaScript property key types (string, number, symbol)
  • All validation methods work with TypeScript type guards for compile-time type narrowing
  • Multi-value validation is efficient for batch operations and configuration validation

Install with Tessl CLI

npx tessl i tessl/npm-sindresorhus--is

docs

assertions.md

async.md

collections.md

index.md

numbers.md

objects.md

primitives.md

strings.md

typed-arrays.md

validation.md

web-apis.md

tile.json