UNPKG

@knighttower/type-check

Version:
1,517 lines (1,165 loc) โ€ข 40.5 kB
# typeCheck JS ## A simple type checker for JavaScript typeCheck JS is a JavaScript library designed for fast and efficient type checking. Inspired by [gkz/type-check](https://github.com/gkz/type-check), this library aims to overcome the limitations and complexities associated with TypeScript. It offers a lightweight, memory-efficient, and easy-to-use solution for both basic and complex type-checking requirements. [![release version](https://github.com/knighttower/typeCheckJs/actions/workflows/pre-release.yml/badge.svg)](https://github.com/knighttower/typeCheckJs/actions/workflows/pre-release.yml) [![NPM published](https://github.com/knighttower/typeCheckJs/actions/workflows/to-npm.yml/badge.svg)](https://github.com/knighttower/typeCheckJs/actions/workflows/to-npm.yml) --- ## ๐Ÿ“š Table of Contents - [Installation](#-installation) - [Quick Start](#-quick-start) - [Why typeCheck JS?](#-why-typecheck-js) - [What does it solve?](#-what-does-it-solve) - [API Reference](#-api-reference) - [typeCheck()](#typecheck) - [_typeCheck()](#_typecheck) - [validType()](#validtype) - [_tc()](#_tc) - [_tcx()](#_tcx) - [addTypeTest()](#addtypetest) - [Type Patterns](#-type-patterns) - [Examples](#-examples) - [Performance](#-performance) - [Tests](#-tests) --- ### ๐Ÿ”ง Installation #### Via npm ```bash npm i @knighttower/type-check # or yarn add @knighttower/type-check # or # as part of a monorepo npm i knighttower # then import {typeCheck} from 'knighttower/type-check'; ``` #### In the Browser ```html <script src="https://cdn.jsdelivr.net/npm/@knighttower/type-check@latest/dist/browser/typeCheck.min.js"></script> <!-- OR as ESM --> <script type="module"> import { typeCheck } from 'https://esm.run/@knighttower/type-check@latest/index.js'; </script> ``` > Note: by default the library is ESM, but other builds are available in the dist folder (CJS, UMD, IIFE, etc.) --- ### ๐Ÿ“ฆ Files | File | Size | | ---------------- | ----- | | /typeCheck.js | 8 KiB | | /typeCheck.js.br | 3 KiB | | /typeCheck.js.gz | 3 KiB | You can also import from the `/src` folder for ESM + JS `next`, or from `/index.js` and `/index.cjs.js` as needed. --- ## ๐Ÿ’ก Why typeCheck JS? 1. **Lightweight**: Adds minimal overhead to your project (\~6k GZip). 2. **Fast Performance**: Micro Optimized for runtime operations. 3. **Ease of Use**: Simple API and pattern syntax. 4. **No Compile Step**: Works directly in vanilla JS. 5. **Complementary**: Works alongside TypeScript for runtime enforcement. 6. **Supports**: callbacks, custom messages, logs, and error throwing. 7. **Flexible**: Supports piped types, optional keys, wildcard matching. 8. **Extensible**: You can register custom test types. 9. **Fully Tested**: Using Vitest for all cases. 10. **Documented**: Full JSDoc for all major methods and patterns. --- ## โ“ What does it solve? * Enforces runtime type checking in production builds. * Helps validate user inputs, API data, and 3rd-party sources. * Avoids unnecessary adoption of TypeScript for small apps. * Solves the issue of type loss in runtime JS after TS transpilation. * Works directly in browsers or legacy JS environments. * Helps library authors enforce expected types at runtime. --- --- ## ๐Ÿšซ What it doesn't solve * It doesn't stop bad programming decisions. --- ## ๐Ÿ“‹ API Reference ### `typeCheck()` **Basic type validation with strict error throwing** ```javascript typeCheck(valueToTest, typeExpression, options?) ``` **Parameters:** - `valueToTest` (any) - The value to validate - `typeExpression` (string) - The type pattern to match against - `options` (object|string, optional) - Configuration options **Returns:** `true` on success, throws error on failure **Examples:** ```javascript import { typeCheck } from '@knighttower/type-check'; // Basic types typeCheck(123, 'number'); // โœ… passes typeCheck('hello', 'string'); // โœ… passes typeCheck(true, 'boolean'); // โœ… passes // Will throw errors typeCheck('hello', 'number'); // โŒ throws TypeError typeCheck(123, 'string'); // โŒ throws TypeError // Optional types typeCheck(null, 'string?'); // โœ… passes (null/undefined allowed) typeCheck(undefined, 'number?'); // โœ… passes typeCheck('hello', 'string?'); // โœ… passes // Union types typeCheck(123, 'string|number'); // โœ… passes (either type allowed) typeCheck('hi', 'string|number'); // โœ… passes // Arrays typeCheck([1, 2, 3], '[number]'); // โœ… all elements are numbers typeCheck([1, 'hi', 3], '[number, string, number]'); // โœ… exact positions match // Objects typeCheck({ name: 'John', age: 30 }, '{name: string, age: number}'); // โœ… typeCheck({ x: 1, y: 2 }, '{any: number}'); // โœ… all values are numbers // Custom error message typeCheck(123, 'string', { error: 'Value must be a string!' }); // With callback for additional validation typeCheck({ id: 1 }, '{id: number}', (result) => { console.log('Validation result:', result); }); ``` --- ### `_typeCheck()` **Advanced type validation with chainable methods** ```javascript _typeCheck(valueToTest, typeExpression, options?) ``` **Parameters:** - Same as `typeCheck()` but returns a chainable object instead of throwing immediately **Chainable Methods:** - `.test()` - Returns boolean result - `.bool` - Direct boolean property access - `.log()` - Logs validation details to console - `.fail()` - Throws error if validation fails - `.return()` - Returns the original value **Examples:** ```javascript import { _typeCheck } from '@knighttower/type-check'; // Get boolean result without throwing const isValid = _typeCheck(123, 'number').test(); // true // Chain methods for debugging _typeCheck({ name: 'John' }, '{name: string}') .log() // logs validation details .fail() // throws if invalid .return(); // returns original value // Conditional validation if (_typeCheck(userInput, 'string').test()) { // Safe to use userInput as string console.log(userInput.toUpperCase()); } // Direct boolean access const isNumber = _typeCheck(value, 'number').bool; // Custom options _typeCheck(data, 'object', { log: true, // auto-log results fail: true, // auto-fail on error callback: (result) => { console.log('Custom validation logic', result); } }); ``` --- ### `validType()` **Simple boolean validation without throwing errors** ```javascript validType(valueToTest, typeExpression) ``` **Parameters:** - `valueToTest` (any) - The value to validate - `typeExpression` (string) - The type pattern to match against **Returns:** `boolean` - true if valid, false if invalid **Examples:** ```javascript import { validType } from '@knighttower/type-check'; // Safe validation for conditional logic if (validType(userInput, 'string')) { // userInput is definitely a string processString(userInput); } else { console.log('Invalid input type'); } // Form validation function validateForm(data) { const errors = []; if (!validType(data.email, 'string')) { errors.push('Email must be a string'); } if (!validType(data.age, 'number')) { errors.push('Age must be a number'); } if (!validType(data.preferences, '{theme: string, notifications: boolean}')) { errors.push('Invalid preferences object'); } return errors; } // API response validation function handleApiResponse(response) { if (validType(response, '{data: array, status: number}')) { return response.data; } throw new Error('Invalid API response format'); } ``` --- ### `_tc()` **Function wrapper with input parameter validation** ```javascript _tc(typeExpressions, functionToWrap, options?) ``` **Parameters:** - `typeExpressions` (array) - Array of type patterns for each parameter - `functionToWrap` (function) - The function to wrap with validation - `options` (object, optional) - Configuration options **Returns:** Wrapped function that validates inputs before execution **Examples:** ```javascript import { _tc } from '@knighttower/type-check'; // Basic function wrapping const greet = _tc(['string'], function(name) { return `Hello, ${name}!`; }); greet('Alice'); // โœ… returns "Hello, Alice!" greet(123); // โŒ throws error // Multiple parameters const calculate = _tc(['number', 'number', 'string'], function(a, b, operation) { switch(operation) { case 'add': return a + b; case 'multiply': return a * b; default: return 0; } }); calculate(5, 3, 'add'); // โœ… returns 8 calculate('5', 3, 'add'); // โŒ throws error // With options const processUser = _tc( ['{name: string, age: number}'], function(user) { return `Processing user: ${user.name}, age: ${user.age}`; }, { log: false, // don't log by default fail: true, // throw errors (default) error: 'Invalid user object provided' } ); // Arrow functions const multiply = _tc(['number', 'number'], (a, b) => a * b); // Complex type validation const createOrder = _tc( ['{items: [object], total: number, customer: {id: number, email: string}}'], function(orderData) { // Function implementation return { orderId: Date.now(), ...orderData }; } ); ``` --- ### `_tcx()` **Function wrapper with input AND output validation** ```javascript _tcx(typeExpressions, functionToWrap, options?) ``` **Parameters:** - `typeExpressions` (array) - Array of type patterns for each parameter - `functionToWrap` (function) - The function to wrap with validation - `options` (object, optional) - Configuration options including `validOutput` **Chainable Methods:** - `.log()` - Log validation details - `.fail()` - Throw error if validation fails - `.return()` - Get the return value - `.test()` - Get boolean validation result **Examples:** ```javascript import { _tcx } from '@knighttower/type-check'; // Function with return value validation const getLength = _tcx( ['string'], (str) => str.length, { validOutput: 'number' } ); const length = getLength('hello').return(); // 5 getLength(123); // โŒ throws (invalid input) // Complex example with chaining const processData = _tcx( ['{data: array}'], function(input) { return { processed: true, count: input.data.length, summary: 'Data processed successfully' }; }, { validOutput: '{processed: boolean, count: number, summary: string}', log: false } ); const result = processData({ data: [1, 2, 3] }) .log() // logs validation details .fail() // throws if validation fails .return(); // returns the actual result // Mathematical operations with validation const divide = _tcx( ['number', 'number'], (a, b) => { if (b === 0) throw new Error('Division by zero'); return a / b; }, { validOutput: 'number' } ); const result = divide(10, 2).return(); // 5 // API function wrapper const fetchUser = _tcx( ['number'], async function(userId) { const response = await fetch(`/api/users/${userId}`); return await response.json(); }, { validOutput: '{id: number, name: string, email: string}', error: 'Invalid user data received from API' } ); // Usage with async const user = await fetchUser(123).fail().return(); ``` --- ### `addTypeTest()` **Register custom type validators** ```javascript addTypeTest(name, validationFunction) ``` **Parameters:** - `name` (string) - Name of the custom type - `validationFunction` (function) - Function that returns boolean for validation **Returns:** `true` if added successfully, error message if name already exists **Examples:** ```javascript import { addTypeTest, typeCheck } from '@knighttower/type-check'; // Custom validator for even numbers addTypeTest('even', (value) => { return typeof value === 'number' && value % 2 === 0; }); typeCheck(4, 'even'); // โœ… passes typeCheck(3, 'even'); // โŒ throws typeCheck([2, 4, 6], '[even]'); // โœ… all even numbers // Email validation addTypeTest('email', (value) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return typeof value === 'string' && emailRegex.test(value); }); typeCheck('user@example.com', 'email'); // โœ… typeCheck('invalid-email', 'email'); // โŒ // Non-empty string addTypeTest('nonEmptyString', (value) => { return typeof value === 'string' && value.trim().length > 0; }); // Positive number addTypeTest('positive', (value) => { return typeof value === 'number' && value > 0; }); // Use in complex validations typeCheck({ name: 'John Doe', email: 'john@example.com', age: 25 }, '{name: nonEmptyString, email: email, age: positive}'); // URL validation addTypeTest('url', (value) => { try { new URL(value); return true; } catch { return false; } }); // Date string validation addTypeTest('dateString', (value) => { return typeof value === 'string' && !isNaN(Date.parse(value)); }); // Use custom types in arrays and objects typeCheck(['2023-01-01', '2023-12-31'], '[dateString]'); typeCheck({ homepage: 'https://example.com', created: '2023-01-01' }, '{homepage: url, created: dateString}'); ``` --- ## ๐Ÿ”ค Type Patterns --- ## ๐Ÿš€ Usage ```javascript import { typeCheck } from '@knighttower/type-check'; typeCheck(123, 'number'); // โœ… typeCheck('hello', 'number'); // โŒ throws ``` --- ### ๐Ÿ‘‰ IMPORTANT The API for the direct `typeCheck()` function uses the familiar `value, type` order: ```js typeCheck(valueToTest, typeExpression); ``` --- ## โšก Quick Start ```javascript typeCheck('hello', 'string'); // โœ… typeCheck([1, 2], '[number]'); // โœ… typeCheck({ x: 1 }, '{x: number}'); // โœ… ``` --- ## ๐Ÿงช Examples ```javascript // With optional arguments typeCheck(null, 'string?'); // true typeCheck(undefined, 'string?'); // true typeCheck('str', 'string?'); // true typeCheck(null, 'string?', options); typeCheck(null, 'string?', 'error message'); // throws error with custom message // Piped typeCheck(1, 'string | number'); // true typeCheck('str', 'string | int'); // true // Array typeCheck([1], '[number]'); // true typeCheck([1, 2, 3], '[number]'); // true typeCheck([1, 3, null], '[number, number, string]'); // Matches the index of the array // Object typeCheck({ x: 'string', y: 10 }, '{x: string, y: number}'); // true typeCheck({ x: 'string', y: 'str' }, '{x: string, y: number}'); // false typeCheck({ x: 'string', y: 10, z: 10 }, '{x: string, y: number}'); // false typeCheck({ x: 2, y: 10 }, '{x: string|number, y: number}'); // true // Object with optional keys typeCheck({ x: 'string', y: 10 }, '{x: string, y: number, z?: number}'); // true // Object with specific keys to test all other ignore typeCheck({ x: 'string', y: 10, z: 20 }, '{x: string, y: number, ...}'); // true // Object with specific keys to test all test a common test method typeCheck({ x: 'string', y: 10, z: 20 }, '{x: string, y: number, any: number}'); // true // Nested arrays or objects typeCheck([1, { x: 'string', y: 10, z: 20 }, 3], '[number, {any: number, x: string}, number]'); // true // With callback functions _typeCheck({ x: 'string', y: 10 }, '{y: number, x: string}', ($this) => { console.log('__testLogHere__', $this); }).log(); //with log function to see the results in the console _typeCheck({ x: 'string', y: 10 }, '{y: number, x: string}').log(); //with fail function to stop execution if the type is not correct _typeCheck({ x: 'string', y: 10 }, '{y: number, x: string}').fail(); // Basic _typeCheck(1, 'number').test(); // true and returns a boolean _typeCheck('1', 'number').fail().test(); // false and throw exception _typeCheck('str', 'string').log().test(); // true and logs the test results ``` --- ## ๐Ÿงฐ Advanced API ### `_typeCheck(valueToTest, testExpression, options?)` ```javascript /** * @param {any} valueToTest * @param {string} testExpression (see below for patterns) * @param {function} callback optional * @return {object} typeCheck Object with chainable methods * @see testUnit for more examples and test cases */ _typeCheck(valueToTest, testExpression, options); // Methods: _typeCheck(..).test(); // returns true or false, helpful for if statements or other logic _typeCheck(..).bool; // same as 'test()', returns true or false, but more direct in the intent _typeCheck(..).log(); // logs the results, helpful for debugging _typeCheck(..).fail(); // throws exception if the test fails. Strict validation enforcement _typeCheck(..).return(); // returns the valueToTest (non chainable with 'test' method) //Chain methods _typeCheck(..).log().test(); _typeCheck(..).fail().test(); _typeCheck(..).log().fail().return(); // Options { log: true, fail: true, callback: function, error: string } ``` <br/> ### validType(valueToTest, testExpression, options); Alias function for \_typeCheck(valueToTest, testExpression, options); It does not do strict validation, but returns a boolean instead of throwing an exception. ```javascript function yourExistingFunction(valueToTest) { validType(valueToTest, 'string'); // your code here } ``` <br/> --- <br/> ### \_tc(testExpression, \_\_function, options); - Wrapper for "typeCheck" (\_tc) to implement functions with type checking. - Does not validate the "return value" of the function. (use "\_tcx" instead). - lightweight, fast and easy to implement. - Does take options. - Does return the 'return value' of the function for each instance. - Note: all test expressions are passed as 'array' like because args are 1 or more. ```js const greet = _tc(['string'], function (name) { return `Hello, ${name}`; }); greet('Alice'); // โœ… greet(123); // โŒ throws ``` ```js const logData = _tc(['number', 'boolean'], (id, active) => { return `${id}:${active}`; }); logData(5, true); // โœ… logData('5', true); // โŒ throws ``` ```javascript const yourCoolFunction = _tc(['number', 'string'], function (myVar, theOtherVar) { // .. your code here }); yourCoolFunction(44.5, 'hello'); // validates that both are numbers // Options { log: false, // default false. Same as method log() fail: false, // default true. Same as method fail() error: string, // custom error message } ``` <br/> --- ### \_tcx(testExpression, \_\_function, options); - Wrapper for "typeCheck" with 'return X' (\_tcx) to implement functions with type checking - Validates the "return value" of the function. - Offers more options. - Has built in features for all its instances. - Does take options. - slighty slower than "\_tc", but more robust for full type checking. - Does not return the 'return value' as '\_tc', instead it has to be explicitly called with '.return()'. - Note: all test expressions are passed as 'array' like because args are 1 or more. ```javascript const yourCoolFunction = _tcx(['number', 'string'], function (myVar, theOtherVar) { // .. your code here return 'hello'; }, {validOutput: 'string'}); yourCoolFunction(44.5, 'hello'); // validates that arg1 is 'number' and arg2 is 'string' and that the return value is a string // Options { validOutput: 'testExpression', // default null. Same as method log() log: false, // default false. Same as method log() fail: false, // default true. Same as method fail() error: string, // custom error message } // Built in features yourCoolFunction(...).log(); // logs the results, helpful for debugging individual functions yourCoolFunction(...).fail(); // throws exception if the test fails. Strict validation enforcement yourCoolFunction(...).return(); // returns the 'return value' (non chainable with 'test' method) yourCoolFunction(...).test(); // returns true or false, helpful for if statements or other logic yourCoolFunction(...).fail().return(); // if the test fails, it will throw exception and if passes returns the 'return value' ``` ```js const getLength = _tcx(['string'], (str) => str.length, { validOutput: 'number', }); getLength('hello').log().return(); // โœ… 5 ``` ```js const sum = _tcx(['number', 'number'], (a, b) => a + b, { validOutput: 'number', }); sum(10, 5).log().fail().return(); // โœ… 15 ``` <br /> --- ### `addTypeTest(name, fn)` Registers a custom type function globally. ```js addTypeTest('even', (x) => typeof x === 'number' && x % 2 === 0); typeCheck(2, 'even'); // โœ… typeCheck(3, 'even'); // โŒ throws typeCheck([2, 4, 6], '[even]'); // โœ… typeCheck({ count: 8 }, '{count: even}'); // โœ… ``` ```js addTypeTest('nonEmptyString', (val) => typeof val === 'string' && val.trim().length > 0 ); typeCheck('hello', 'nonEmptyString'); // โœ… typeCheck('', 'nonEmptyString'); // โŒ ``` --- ## ๐Ÿ”ค Possible Patterns ``` Possible type patterns: // basic string 'type' // only one test 'type | type' // returns to test one or more types 'type?' // is type or null/undefined 'type | type?' // the second type would be type or null/undefined // basic array '[type]' // returns test to test all the keys '[type | type]' // returns test to test all key with one or more '[[type],[type]]' // basic object '{key1: type}' '{key1: type | type}' '{key1: type, key2: type}' '{key1: type, key2?: type}' // if key2 is not present or null/undefined, it will not be tested '{key1: type, key2: type?}' // if key2 is not set or null/undefined, it will not be tested '{key1: type | type, key2: type | type}' '{any: type}' // any key '{any: type | type}' // any key '{key1: type, any: type}' // specific key, and all other "any" '{key1: type | type, ...}' // specific key, and all other no test // ADVANCE // array of objects ## ๐Ÿ”ค Type Patterns TypeCheck JS supports a rich pattern syntax for expressing complex type requirements: ### Basic Types ```javascript // Single type 'string' // must be string 'number' // must be number 'boolean' // must be boolean 'null' // must be null 'undefined' // must be undefined 'array' // must be array 'object' // must be object 'function' // must be function // Optional types (allows null/undefined) 'string?' // string, null, or undefined 'number?' // number, null, or undefined // Union types (multiple allowed types) 'string|number' // string OR number 'boolean|string|number' // any of the three types 'array|object' // array OR object // Combined optional and union 'string|number?' // string, number, null, or undefined ``` ### Array Patterns ```javascript // Homogeneous arrays (all elements same type) '[string]' // array of strings '[number]' // array of numbers '[boolean]' // array of booleans // Heterogeneous arrays (specific positions) '[string, number]' // first element string, second number '[string, number, boolean]' // three elements with specific types '[object, array, string]' // mixed types at specific positions // Union types in arrays '[string|number]' // array where all elements are string OR number '[string, number|boolean]' // first string, second number OR boolean // Nested arrays '[[string]]' // array of string arrays '[string, [number]]' // first string, second is number array '[[string, number]]' // array containing [string, number] pairs // Optional elements in arrays '[string, number?]' // second element optional ``` ### Object Patterns ```javascript // Basic object structure '{name: string}' // object with name property (string) '{name: string, age: number}' // object with name and age properties '{id: number, active: boolean}' // id (number) and active (boolean) // Optional properties '{name: string, age?: number}' // age property is optional '{id: number, email?: string}' // email property is optional // Union types in properties '{status: string|number}' // status can be string OR number '{data: string|array|object}' // data can be multiple types // Any key validation (all properties same type) '{any: string}' // all property values must be strings '{any: number}' // all property values must be numbers '{any: string|number}' // all values string OR number // Mixed specific and any '{id: number, any: string}' // id must be number, others string '{name: string, age: number, any: boolean}' // specific props + others boolean // Ignore extra properties '{name: string, ...}' // name required, ignore other props '{id: number, email: string, ...}' // specified props required, others ignored // Nested objects '{user: {name: string, age: number}}' // nested object structure '{config: {theme: string, debug: boolean}}' // nested configuration object // Complex nested structures '{users: [{id: number, name: string}]}' // array of user objects '{response: {data: [object], meta: {total: number}}}' // complex API response ``` ### Advanced Patterns ```javascript // Enums (specific values only) 'enum=red/green/blue' // only these three values allowed 'enum=small/medium/large' // size enum 'enum=admin/user/guest' // role enum // Enums with other types 'string|enum=active/inactive' // string OR specific enum values 'enum=1/2/3|string' // enum values OR any string // Complex array patterns '[{name: string, tags: [string]}]' // array of objects with string arrays '[string, {count: number}, [boolean]]' // mixed: string, object, boolean array // Real-world examples '{id: number, user: {name: string, email: string}, items: [{id: number, quantity: number}]}' // API response patterns '{data: [object], pagination: {page: number, total: number}, meta: {timestamp: string}}' // Form validation patterns '{email: string, password: string, confirmPassword?: string, terms: boolean}' // Configuration object patterns '{api: {baseUrl: string, timeout: number?}, features: {darkMode: boolean, notifications: boolean}}' ``` ### Pattern Examples with Use Cases ```javascript // User profile validation const userPattern = `{ id: number, email: string, profile: { firstName: string, lastName: string, avatar?: string }, preferences: { theme: enum=light/dark, notifications: boolean }, roles: [enum=admin/user/moderator] }`; // E-commerce order const orderPattern = `{ orderId: string, customer: {id: number, email: string}, items: [{ productId: number, name: string, price: number, quantity: number }], shipping: { address: string, method: enum=standard/express/overnight }, total: number }`; // API response with pagination const apiResponsePattern = `{ data: [object], pagination: { page: number, limit: number, total: number, hasNext: boolean }, meta?: { timestamp: string, version: string } }`; ``` --- ## ๐Ÿ“ Comprehensive Examples ### Form Validation ```javascript import { validType, typeCheck } from '@knighttower/type-check'; function validateRegistrationForm(formData) { const errors = []; // Basic field validation if (!validType(formData.email, 'string')) { errors.push('Email is required'); } if (!validType(formData.password, 'string')) { errors.push('Password is required'); } // Complex object validation if (!validType(formData, '{email: string, password: string, age?: number}')) { errors.push('Invalid form structure'); } // Custom validation with typeCheck for strict enforcement try { typeCheck(formData.preferences, '{newsletter: boolean, theme: enum=light/dark}'); } catch (error) { errors.push('Invalid preferences'); } return errors; } // Usage const formData = { email: 'user@example.com', password: 'securePassword', age: 25, preferences: { newsletter: true, theme: 'dark' } }; const errors = validateRegistrationForm(formData); ``` ### API Data Validation ```javascript import { _typeCheck, addTypeTest } from '@knighttower/type-check'; // Custom validation for ISO date strings addTypeTest('isoDate', (value) => { return typeof value === 'string' && !isNaN(Date.parse(value)); }); // API endpoint with validation async function fetchUserOrders(userId) { // Validate input typeCheck(userId, 'number'); const response = await fetch(`/api/users/${userId}/orders`); const data = await response.json(); // Validate API response structure const isValid = _typeCheck(data, `{ orders: [{ id: number, status: enum=pending/processing/shipped/delivered, items: [{name: string, quantity: number, price: number}], createdAt: isoDate, total: number }], pagination: {page: number, totalPages: number} }`).test(); if (!isValid) { throw new Error('Invalid API response format'); } return data; } ``` ### Function Parameter Validation ```javascript import { _tc, _tcx } from '@knighttower/type-check'; // Database query function with validation const findUsers = _tc( ['{filters?: {name?: string, age?: number, active?: boolean}, limit?: number}'], function(options = {}) { const { filters = {}, limit = 10 } = options; // Build and execute query console.log('Searching users with filters:', filters); return mockDatabaseQuery(filters, limit); } ); // Math function with input and output validation const calculateCompoundInterest = _tcx( ['number', 'number', 'number', 'number'], function(principal, rate, time, compound) { return principal * Math.pow((1 + rate / compound), compound * time); }, { validOutput: 'number' } ); // Usage const users = findUsers({ filters: { active: true, age: 25 }, limit: 5 }); const investment = calculateCompoundInterest(1000, 0.05, 10, 12).return(); ``` ### Configuration Validation ```javascript import { typeCheck, addTypeTest } from '@knighttower/type-check'; // Custom port number validation addTypeTest('port', (value) => { return typeof value === 'number' && value >= 1 && value <= 65535; }); // Application configuration const configPattern = `{ server: { host: string, port: port, ssl: boolean }, database: { url: string, pool: {min: number, max: number} }, features: { auth: boolean, logging: enum=debug/info/warn/error, rateLimit?: { windowMs: number, max: number } } }`; function validateConfig(config) { try { typeCheck(config, configPattern); console.log('Configuration is valid'); return true; } catch (error) { console.error('Configuration error:', error.message); return false; } } // Usage const appConfig = { server: { host: 'localhost', port: 3000, ssl: false }, database: { url: 'postgresql://localhost:5432/myapp', pool: { min: 2, max: 10 } }, features: { auth: true, logging: 'info', rateLimit: { windowMs: 900000, max: 100 } } }; validateConfig(appConfig); ``` ### Real-time Data Validation ```javascript import { _typeCheck } from '@knighttower/type-check'; // WebSocket message validation function handleWebSocketMessage(message) { // Log validation details in development const validation = _typeCheck(message, `{ type: enum=user_joined/user_left/message/typing, payload: { userId: number, username: string, content?: string, timestamp: number } }`).log(); if (!validation.test()) { console.warn('Invalid message format received'); return; } // Process valid message const { type, payload } = message; switch (type) { case 'message': displayMessage(payload); break; case 'user_joined': showUserJoined(payload); break; // ... other cases } } // Event handler validation const handleUserAction = _tc( ['{action: enum=click/hover/focus, target: string, data?: object}'], function(event) { console.log(`User ${event.action} on ${event.target}`); if (event.data) { console.log('Additional data:', event.data); } } ); ``` --- ## โšก Performance '[{key1: type | type}]' // returns test to test all key with one or more '[{key1: type, key2: type}]' // returns '[{key1: type, key2: type}, {key1: type, key2: type}]' '[{key1: type | type, key2: type | type}, {key1: type | type, key2: type | type}]' '[{key1: type, any: type}]' ``` ## โšก Performance TypeCheck JS is designed for production use with minimal performance overhead: ### Benchmarks - **Lightweight**: ~6k gzipped, minimal bundle impact - **Fast Execution**: Micro-optimized for runtime operations - **Caching**: Built-in caching for type patterns and validations - **Memory Efficient**: Reuses validation functions and patterns ### Performance Comparison ```javascript // Benchmark example (1000 iterations) import { _tc, _tcx, typeCheck } from '@knighttower/type-check'; // _tc: ~3ms for 1000 function calls with validation const fastFunction = _tc(['[number]'], (arr) => arr.reduce((a, b) => a + b, 0)); // _tcx: ~4ms for 1000 function calls with input/output validation const robustFunction = _tcx(['[number]'], (arr) => arr.reduce((a, b) => a + b, 0), { validOutput: 'number' }); // Direct typeCheck: ~2ms for 1000 direct validations const numbers = [1, 2, 3, 4, 5]; for (let i = 0; i < 1000; i++) { typeCheck(numbers, '[number]'); } ``` ### Optimization Tips 1. **Reuse wrapped functions**: Create `_tc` and `_tcx` wrapped functions once, use many times 2. **Use `validType()` for boolean checks**: Faster than `_typeCheck().test()` 3. **Cache complex patterns**: The library automatically caches, but avoid recreating patterns 4. **Prefer simpler patterns**: `'string'` is faster than `'string|number|boolean'` --- ## ๐Ÿงช Tests Comprehensive test coverage ensures reliability: ```bash # Run tests npm test # Run tests with coverage npm run test:coverage # Run performance benchmarks npm run benchmark ``` ### Test Files - `tests/TypeCheck.test.js` - Core functionality tests - `tests/TestBuilder.Unit.test.js` - Pattern parsing tests - `tests/BuildExports.unit.test.js` - Export validation tests - `type-patterns.txt` - Extended pattern examples ### Example Test Cases ```javascript // Basic type validation expect(validType(123, 'number')).toBe(true); expect(validType('hello', 'number')).toBe(false); // Complex object validation expect(validType({ user: { name: 'John', age: 30 }, items: [{ id: 1, name: 'Item' }] }, '{user: {name: string, age: number}, items: [{id: number, name: string}]}')).toBe(true); // Custom type tests addTypeTest('even', x => typeof x === 'number' && x % 2 === 0); expect(validType(4, 'even')).toBe(true); expect(validType(3, 'even')).toBe(false); // Function wrapper tests const fn = _tc(['string'], (str) => str.toUpperCase()); expect(() => fn('hello')).not.toThrow(); expect(() => fn(123)).toThrow(); ``` --- ## ๐Ÿ”ง Advanced Usage ### TypeScript Integration TypeCheck JS works alongside TypeScript for runtime validation: ```typescript import { typeCheck, validType } from '@knighttower/type-check'; interface User { id: number; name: string; email: string; } function processUser(data: unknown): User { // Runtime validation typeCheck(data, '{id: number, name: string, email: string}'); // Now TypeScript knows data is valid return data as User; } // API response validation async function fetchUser(id: number): Promise<User> { const response = await fetch(`/api/users/${id}`); const data = await response.json(); if (!validType(data, '{id: number, name: string, email: string}')) { throw new Error('Invalid user data from API'); } return data; } ``` ### Error Handling ```javascript import { typeCheck, _typeCheck } from '@knighttower/type-check'; // Custom error messages try { typeCheck(invalidData, 'string', { error: 'User input must be a valid string' }); } catch (error) { console.error('Validation failed:', error.message); } // Graceful validation function safeValidation(data, pattern) { const result = _typeCheck(data, pattern); if (!result.test()) { console.warn('Data validation failed for pattern:', pattern); return null; } return result.return(); } // Multiple validation attempts function validateWithFallback(data) { const patterns = [ '{id: number, name: string}', '{id: string, name: string}', '{name: string}' ]; for (const pattern of patterns) { if (validType(data, pattern)) { console.log('Matched pattern:', pattern); return data; } } throw new Error('Data does not match any expected pattern'); } ``` ### Custom Validation Library ```javascript import { addTypeTest, typeCheck } from '@knighttower/type-check'; // Build a custom validation library class CustomValidators { static init() { // Email validation addTypeTest('email', (value) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return typeof value === 'string' && emailRegex.test(value); }); // Phone number validation addTypeTest('phone', (value) => { const phoneRegex = /^\+?[\d\s\-\(\)]+$/; return typeof value === 'string' && phoneRegex.test(value); }); // URL validation addTypeTest('url', (value) => { try { new URL(value); return true; } catch { return false; } }); // Credit card validation (basic) addTypeTest('creditCard', (value) => { const ccRegex = /^\d{4}\s?\d{4}\s?\d{4}\s?\d{4}$/; return typeof value === 'string' && ccRegex.test(value.replace(/\s/g, '')); }); // Strong password validation addTypeTest('strongPassword', (value) => { const strongRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; return typeof value === 'string' && strongRegex.test(value); }); } } // Initialize custom validators CustomValidators.init(); // Use custom validators const userRegistration = { email: 'user@example.com', phone: '+1-555-123-4567', website: 'https://example.com', password: 'MyStr0ng!Pass' }; typeCheck(userRegistration, `{ email: email, phone: phone, website: url, password: strongPassword }`); ``` --- ## ๐Ÿค Contributing We welcome contributions! Here's how to get started: 1. Fork the repository 2. Create a feature branch: `git checkout -b feature-name` 3. Make your changes with tests 4. Run the test suite: `npm test` 5. Submit a pull request ### Development Setup ```bash git clone https://github.com/knighttower/typeCheckJs.git cd typeCheckJs npm install npm test ``` --- ## ๐Ÿ“„ License MIT License - see LICENSE file for details. --- ## ๐Ÿ”— Related Projects Check out other tools in the Knight Tower ecosystem: - [Utility JS](https://knighttower.io) - Additional JavaScript utilities - [DOM Observer](https://github.com/knighttower/dom-observer) - DOM change detection - [Proxy Object](https://github.com/knighttower/proxy-object) - Object state management --- <br /><br /> Check out other cool stuff at https://knighttower.io and help support open source projects. <br /> ## ๐Ÿ™Œ Sponsored By [![Squarefox](https://github.com/knighttower/typeCheckJs/assets/649334/024f2e7d-d3d0-4558-8893-2e6bbea29a6f)](https://squarefox.us/)