UNPKG

guardz

Version:

A simple and lightweight TypeScript type guard library for runtime type validation.

82 lines (81 loc) 3.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isOneOfTypes = isOneOfTypes; const stringify_1 = require("../stringify"); const getExpectedTypeName_1 = require("../utils/getExpectedTypeName"); /** * Creates a type guard that checks if a value matches at least one of several type guards. * * This is different from `isOneOf` which checks against literal values. This function * combines multiple type guard functions and returns true if the value passes any of them. * Useful for union types where each type needs its own validation logic. * * @template T - The union type of all possible types * @param typeGuards - Array of type guard functions to check against * @returns A type guard function that validates against any of the provided type guards * * @example * ```typescript * import { isOneOfTypes, isString, isNumber, isBoolean, isType } from 'guardz'; * * // Simple union types * const isStringOrNumber = isOneOfTypes(isString, isNumber); * const isPrimitive = isOneOfTypes(isString, isNumber, isBoolean); * * console.log(isStringOrNumber("hello")); // true * console.log(isStringOrNumber(42)); // true * console.log(isStringOrNumber(true)); // false * * // Complex union types * interface User { * type: "user"; * name: string; * } * * interface Admin { * type: "admin"; * permissions: string[]; * } * * const isUser = isType<User>({ type: isEqualTo("user"), name: isString }); * const isAdmin = isType<Admin>({ type: isEqualTo("admin"), permissions: isArrayWithEachItem(isString) }); * const isPerson = isOneOfTypes(isUser, isAdmin); * * const data: unknown = getUserInput(); * if (isPerson(data)) { * // data is now typed as User | Admin * console.log(data.type); // TypeScript knows this exists on both types * } * ``` */ function isOneOfTypes(...typeGuards) { return function (value, config) { // Collect validation results to avoid duplicate checks const validationResults = typeGuards.map(typeGuard => ({ typeGuard, isValid: typeGuard(value, null) })); const isValid = validationResults.some(result => result.isValid); if (!isValid && config) { const valueString = (0, stringify_1.stringify)(value); const displayValue = valueString.length > 200 ? config.identifier : `${config.identifier} (${valueString})`; const errorMessages = [ `Expected ${displayValue} type to match one of "${typeGuards.map(fn => (0, getExpectedTypeName_1.getTypeGuardDisplayName)(fn)).join(' | ')}"`, ]; // Use the validation results we already collected validationResults.forEach(({ typeGuard }) => typeGuard(value, { ...config, callbackOnError: error => { const newError = `- ${error}`; if (!errorMessages.includes(newError)) { errorMessages.push(newError); } }, })); config.callbackOnError(errorMessages.join('\n')); } return isValid; }; }