├── .commitlintrc ├── .github ├── dependabot.yaml └── workflows │ ├── ci.yaml │ └── release.yaml ├── .gitignore ├── .npmrc ├── .prettierrc ├── LICENSE ├── README.md ├── SECURITY.md ├── eslint.config.mjs ├── package.json ├── pnpm-lock.yaml ├── src ├── assertions │ ├── assertIsAnyArrayBuffer.ts │ ├── assertIsArgumentsObject.ts │ ├── assertIsArray.ts │ ├── assertIsArrayBuffer.ts │ ├── assertIsArrayBufferView.ts │ ├── assertIsAsyncFunction.ts │ ├── assertIsAsyncGenerator.ts │ ├── assertIsAsyncGeneratorFunction.ts │ ├── assertIsAsyncIterable.ts │ ├── assertIsBigInt.ts │ ├── assertIsBigIntObject.ts │ ├── assertIsBoolean.ts │ ├── assertIsBooleanObject.ts │ ├── assertIsBoxedPrimitive.ts │ ├── assertIsBuffer.ts │ ├── assertIsDataView.ts │ ├── assertIsDate.ts │ ├── assertIsDefined.ts │ ├── assertIsEmptyArray.ts │ ├── assertIsEmptyObject.ts │ ├── assertIsEmptyString.ts │ ├── assertIsError.ts │ ├── assertIsFinite.ts │ ├── assertIsFunction.ts │ ├── assertIsGenerator.ts │ ├── assertIsGeneratorFunction.ts │ ├── assertIsInteger.ts │ ├── assertIsIterable.ts │ ├── assertIsIterator.ts │ ├── assertIsMap.ts │ ├── assertIsMapIterator.ts │ ├── assertIsNaN.ts │ ├── assertIsNativeError.ts │ ├── assertIsNonEmptyArray.ts │ ├── assertIsNonEmptyString.ts │ ├── assertIsNotNull.ts │ ├── assertIsNotNullish.ts │ ├── assertIsNull.ts │ ├── assertIsNullish.ts │ ├── assertIsNumber.ts │ ├── assertIsNumberObject.ts │ ├── assertIsObject.ts │ ├── assertIsPlainObject.ts │ ├── assertIsPromise.ts │ ├── assertIsRecord.ts │ ├── assertIsRegExp.ts │ ├── assertIsSafeInteger.ts │ ├── assertIsSet.ts │ ├── assertIsSetIterator.ts │ ├── assertIsSharedArrayBuffer.ts │ ├── assertIsString.ts │ ├── assertIsStringObject.ts │ ├── assertIsSymbol.ts │ ├── assertIsSymbolObject.ts │ ├── assertIsTypedArray.ts │ ├── assertIsUndefined.ts │ ├── assertIsWeakMap.ts │ └── assertIsWeakSet.ts ├── guards │ ├── isAnyArrayBuffer.ts │ ├── isArgumentsObject.ts │ ├── isArray.ts │ ├── isArrayBuffer.ts │ ├── isArrayBufferView.ts │ ├── isAsyncFunction.ts │ ├── isAsyncGenerator.ts │ ├── isAsyncGeneratorFunction.ts │ ├── isAsyncIterable.ts │ ├── isBigInt.ts │ ├── isBigIntObject.ts │ ├── isBoolean.ts │ ├── isBooleanObject.ts │ ├── isBoxedPrimitive.ts │ ├── isBuffer.ts │ ├── isDataView.ts │ ├── isDate.ts │ ├── isDefined.ts │ ├── isEmptyArray.ts │ ├── isEmptyObject.ts │ ├── isEmptyString.ts │ ├── isError.ts │ ├── isFinite.ts │ ├── isFunction.ts │ ├── isGenerator.ts │ ├── isGeneratorFunction.ts │ ├── isInteger.ts │ ├── isIterable.ts │ ├── isIterator.ts │ ├── isMap.ts │ ├── isMapIterator.ts │ ├── isNaN.ts │ ├── isNativeError.ts │ ├── isNonEmptyArray.ts │ ├── isNonEmptyString.ts │ ├── isNotNull.ts │ ├── isNotNullish.ts │ ├── isNull.ts │ ├── isNullish.ts │ ├── isNumber.ts │ ├── isNumberObject.ts │ ├── isObject.ts │ ├── isPlainObject.ts │ ├── isPromise.ts │ ├── isRecord.ts │ ├── isRegExp.ts │ ├── isSafeInteger.ts │ ├── isSet.ts │ ├── isSetIterator.ts │ ├── isSharedArrayBuffer.ts │ ├── isString.ts │ ├── isStringObject.ts │ ├── isSymbol.ts │ ├── isSymbolObject.ts │ ├── isTypedArray.ts │ ├── isUndefined.ts │ ├── isWeakMap.ts │ └── isWeakSet.ts ├── index.ts ├── types.ts └── utils.ts ├── tests ├── assertions.spec.ts ├── guards.spec.ts └── utils.spec.ts ├── tsconfig.json └── vite.config.ts /.commitlintrc: -------------------------------------------------------------------------------- 1 | { "extends": ["@commitlint/config-conventional"] } 2 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | - name: Install Node.js 16 | uses: actions/setup-node@v4 17 | - uses: pnpm/action-setup@v4 18 | name: Install pnpm 19 | - name: Install Dependencies 20 | run: pnpm install 21 | - name: test 22 | run: pnpm run test 23 | lint: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v4 28 | - name: Install Node.js 29 | uses: actions/setup-node@v4 30 | - uses: pnpm/action-setup@v4 31 | name: Install pnpm 32 | - name: Install Dependencies 33 | run: pnpm install 34 | - name: lint 35 | run: pnpm run lint 36 | typecheck: 37 | runs-on: ubuntu-latest 38 | steps: 39 | - name: Checkout 40 | uses: actions/checkout@v4 41 | - name: Install Node.js 42 | uses: actions/setup-node@v4 43 | - uses: pnpm/action-setup@v4 44 | name: Install pnpm 45 | - name: Install Dependencies 46 | run: pnpm install 47 | - name: typecheck 48 | run: pnpm run typecheck 49 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: PNPM Publish 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | - name: Install Node.js 14 | uses: actions/setup-node@v4 15 | - uses: pnpm/action-setup@v4 16 | name: Install pnpm 17 | - name: Install Dependencies 18 | run: pnpm install 19 | - name: Build 20 | run: pnpm build 21 | - name: Publish 22 | run: | 23 | pnpm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }} 24 | pnpm publish 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.tsbuildinfo 3 | .husky/ 4 | .idea/ 5 | coverage/ 6 | dist/ 7 | node_modules/ -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-jsdoc"], 3 | "tsdoc": true, 4 | "trailingComma": "all", 5 | "tabWidth": 4, 6 | "semi": true, 7 | "quoteProps": "consistent", 8 | "singleQuote": true 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2025 Na'aman Hirschfeld 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @tool-belt/type-predicates 2 | 3 | [![npm version](https://img.shields.io/npm/v/@tool-belt/type-predicates.svg)](https://www.npmjs.com/package/@tool-belt/type-predicates) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 5 | 6 | A comprehensive collection of performant type guards and assertions with excellent TypeScript support. This library serves as a drop-in replacement for Node.js's `util/types` module, while offering significantly better type inference, more extensive functionality, and cross-platform compatibility. 7 | 8 | ## Features 9 | 10 | - 🚀 **Better TypeScript Support**: Advanced type inference with generics and precise type narrowing 11 | - 📦 **Zero Dependencies**: Lightweight and self-contained 12 | - 🌳 **Tree-Shakeable**: Full ESM support for optimal bundle sizes 13 | - 🌐 **Cross-Platform**: Works in browsers, Node.js, and any JavaScript environment 14 | - ✅ **Thorough Testing**: Comprehensive test coverage for both runtime behavior and type safety 15 | - 🔧 **Extensive API**: More comprehensive than Node.js built-in utilities 16 | - 🎯 **Type Guards & Assertions**: Every type check is available in both guard and assertion forms 17 | 18 | ## Installation 19 | 20 | ```bash 21 | npm install @tool-belt/type-predicates 22 | ``` 23 | 24 | ```bash 25 | pnpm add @tool-belt/type-predicates 26 | ``` 27 | 28 | ```bash 29 | yarn add @tool-belt/type-predicates 30 | ``` 31 | 32 | ## Browser Support 33 | 34 | This library works in all modern browsers and Node.js environments. It's compiled to ES modules and CommonJS, with full support for tree-shaking to minimize bundle size. 35 | 36 | ## Key Differences from `node:util/types` 37 | 38 | ### 1. Superior TypeScript Support 39 | 40 | ```typescript 41 | // node:util/types 42 | import { isArray } from 'util/types'; 43 | const arr: unknown = ['a', 'b', 'c']; 44 | if (isArray(arr)) { 45 | // arr is typed as "unknown[]" - not very useful 46 | } 47 | 48 | // @tool-belt/type-predicates 49 | import { isArray } from '@tool-belt/type-predicates'; 50 | const arr: unknown = ['a', 'b', 'c']; 51 | if (isArray(arr)) { 52 | // arr is typed as "string[]" - much better! 53 | } 54 | ``` 55 | 56 | ### 2. Type Assertions 57 | 58 | ```typescript 59 | import { assertIsString, assertIsArray } from '@tool-belt/type-predicates'; 60 | 61 | // Throws TypeError if not a string 62 | assertIsString(value); 63 | // After this line, TypeScript knows 'value' is a string 64 | 65 | // With custom error messages 66 | assertIsArray(data, { message: 'Configuration must be an array' }); 67 | 68 | // With nested validation 69 | assertIsArray(data, { 70 | valueValidator: (item) => typeof item === 'number', 71 | message: 'Expected array of numbers', 72 | }); 73 | ``` 74 | 75 | ### 3. Composable Type Guards 76 | 77 | ```typescript 78 | import { 79 | isUnion, 80 | isString, 81 | isNumber, 82 | createTypeGuard, 83 | } from '@tool-belt/type-predicates'; 84 | 85 | // Combine multiple type guards 86 | const isStringOrNumber = isUnion(isString, isNumber); 87 | 88 | // Create custom type guards 89 | const isPositiveNumber = createTypeGuard( 90 | (value) => isNumber(value) && value > 0, 91 | ); 92 | ``` 93 | 94 | ## API Overview 95 | 96 | ### Type Guards 97 | 98 | Every guard returns a type predicate for TypeScript type narrowing: 99 | 100 | ```typescript 101 | import { 102 | isArray, 103 | isObject, 104 | isString, 105 | isNumber, 106 | isBoolean, 107 | isFunction, 108 | isPromise, 109 | isMap, 110 | isSet, 111 | isDate, 112 | isRegExp, 113 | isError, 114 | isNull, 115 | isUndefined, 116 | isNullish, 117 | isDefined, 118 | // ... and many more 119 | } from '@tool-belt/type-predicates'; 120 | 121 | // Use in conditionals 122 | if (isString(value)) { 123 | // TypeScript knows 'value' is a string here 124 | console.log(value.toUpperCase()); 125 | } 126 | 127 | // Use with array methods 128 | const strings = mixedArray.filter(isString); 129 | // strings is typed as string[] 130 | ``` 131 | 132 | ### Type Assertions 133 | 134 | Every guard has a corresponding assertion that throws on failure: 135 | 136 | ```typescript 137 | import { 138 | assertIsArray, 139 | assertIsObject, 140 | assertIsString, 141 | // ... all guards have assertion versions 142 | } from '@tool-belt/type-predicates'; 143 | 144 | function processConfig(config: unknown) { 145 | assertIsObject(config); 146 | // TypeScript now knows config is an object 147 | 148 | assertIsString(config.name, { message: 'Config name must be a string' }); 149 | // config.name is now typed as string 150 | } 151 | ``` 152 | 153 | ### Advanced Features 154 | 155 | #### Deep Validation 156 | 157 | ```typescript 158 | import { isArray, isObject, isString } from '@tool-belt/type-predicates'; 159 | 160 | // Validate array elements 161 | const isStringArray = (value: unknown): value is string[] => 162 | isArray(value, { valueValidator: isString }); 163 | 164 | // Validate object values 165 | const isStringRecord = (value: unknown): value is Record => 166 | isObject(value, { valueValidator: isString }); 167 | ``` 168 | 169 | #### Utility Functions 170 | 171 | ```typescript 172 | import { createTypeGuard, isUnion } from '@tool-belt/type-predicates'; 173 | 174 | // Create custom guards 175 | const isNonEmptyString = createTypeGuard( 176 | (value) => isString(value) && value.length > 0, 177 | ); 178 | 179 | // Union types 180 | const isNumberOrString = isUnion(isNumber, isString); 181 | ``` 182 | 183 | ## Complete API Reference 184 | 185 | ### Basic Types 186 | 187 | - `isString` / `assertIsString` 188 | - `isNumber` / `assertIsNumber` 189 | - `isBoolean` / `assertIsBoolean` 190 | - `isBigInt` / `assertIsBigInt` 191 | - `isSymbol` / `assertIsSymbol` 192 | - `isUndefined` / `assertIsUndefined` 193 | - `isNull` / `assertIsNull` 194 | - `isNullish` / `assertIsNullish` 195 | - `isDefined` / `assertIsDefined` 196 | - `isNotNull` / `assertIsNotNull` 197 | - `isNotNullish` / `assertIsNotNullish` 198 | 199 | ### Object Types 200 | 201 | - `isObject` / `assertIsObject` - Checks if value is an object (not null) 202 | - `isPlainObject` / `assertIsPlainObject` - Checks if value is a plain object (not a class instance) 203 | - `isRecord` / `assertIsRecord` - Validates an object with specific key and value types 204 | - `isEmptyObject` / `assertIsEmptyObject` - Checks if object has no own properties 205 | - `isBoxedPrimitive` / `assertIsBoxedPrimitive` - Checks if value is a boxed primitive 206 | 207 | ### Collection Types 208 | 209 | - `isArray` / `assertIsArray` - Validates arrays with optional element type checking 210 | - `isEmptyArray` / `assertIsEmptyArray` - Checks if array has length of 0 211 | - `isNonEmptyArray` / `assertIsNonEmptyArray` - Checks if array has length > 0 212 | - `isMap` / `assertIsMap` - Validates Map objects with optional key/value type checking 213 | - `isSet` / `assertIsSet` - Validates Set objects with optional value type checking 214 | - `isWeakMap` / `assertIsWeakMap` - Checks if value is a WeakMap 215 | - `isWeakSet` / `assertIsWeakSet` - Checks if value is a WeakSet 216 | 217 | ### Function Types 218 | 219 | - `isFunction` / `assertIsFunction` - Checks if value is a function 220 | - `isAsyncFunction` / `assertIsAsyncFunction` - Checks if value is an async function 221 | - `isGeneratorFunction` / `assertIsGeneratorFunction` - Checks if value is a generator function 222 | - `isAsyncGeneratorFunction` / `assertIsAsyncGeneratorFunction` - Checks if value is an async generator function 223 | 224 | ### Iterator Types 225 | 226 | - `isIterable` / `assertIsIterable` - Validates iterable objects 227 | - `isIterator` / `assertIsIterator` - Validates iterator objects 228 | - `isGenerator` / `assertIsGenerator` - Checks if value is a generator 229 | - `isAsyncGenerator` / `assertIsAsyncGenerator` - Checks if value is an async generator 230 | - `isAsyncIterable` / `assertIsAsyncIterable` - Validates async iterable objects 231 | - `isMapIterator` / `assertIsMapIterator` - Checks if value is a Map iterator 232 | - `isSetIterator` / `assertIsSetIterator` - Checks if value is a Set iterator 233 | 234 | ### Error Types 235 | 236 | - `isError` / `assertIsError` - Checks if value is an Error 237 | - `isNativeError` / `assertIsNativeError` - Checks if value is a native Error type 238 | 239 | ### Number Utilities 240 | 241 | - `isNaN` / `assertIsNaN` - Checks if value is NaN 242 | - `isFinite` / `assertIsFinite` - Checks if value is a finite number 243 | - `isInteger` / `assertIsInteger` - Checks if value is an integer 244 | - `isSafeInteger` / `assertIsSafeInteger` - Checks if value is a safe integer 245 | 246 | ### String Utilities 247 | 248 | - `isEmptyString` / `assertIsEmptyString` - Checks if string has length of 0 249 | - `isNonEmptyString` / `assertIsNonEmptyString` - Checks if string has length > 0 250 | 251 | ### Buffer and TypedArray Types 252 | 253 | - `isBuffer` / `assertIsBuffer` - Checks if value is a Buffer 254 | - `isArrayBuffer` / `assertIsArrayBuffer` - Checks if value is an ArrayBuffer 255 | - `isSharedArrayBuffer` / `assertIsSharedArrayBuffer` - Checks if value is a SharedArrayBuffer 256 | - `isAnyArrayBuffer` / `assertIsAnyArrayBuffer` - Checks if value is any kind of ArrayBuffer 257 | - `isArrayBufferView` / `assertIsArrayBufferView` - Checks if value is an ArrayBufferView 258 | - `isDataView` / `assertIsDataView` - Checks if value is a DataView 259 | - `isTypedArray` / `assertIsTypedArray` - Checks if value is any TypedArray 260 | - Various specific TypedArray checkers (Int8Array, Uint8Array, etc.) 261 | 262 | ### Other Built-in Types 263 | 264 | - `isDate` / `assertIsDate` - Checks if value is a Date 265 | - `isRegExp` / `assertIsRegExp` - Checks if value is a RegExp 266 | - `isPromise` / `assertIsPromise` - Checks if value is a Promise 267 | - `isArgumentsObject` / `assertIsArgumentsObject` - Checks if value is an arguments object 268 | 269 | ## Creating Custom Type Guards 270 | 271 | You can create your own type guards using the `createTypeGuard` utility: 272 | 273 | ```typescript 274 | import { createTypeGuard, isNumber } from '@tool-belt/type-predicates'; 275 | 276 | // Create a type guard for positive numbers 277 | const isPositiveNumber = createTypeGuard( 278 | (value) => isNumber(value) && value > 0, 279 | ); 280 | 281 | // Use it like any other guard 282 | if (isPositiveNumber(value)) { 283 | // TypeScript knows value is a number here 284 | // Runtime has verified value > 0 285 | } 286 | ``` 287 | 288 | ## Error Handling Examples 289 | 290 | ```typescript 291 | import { isError } from '@tool-belt/type-predicates'; 292 | 293 | try { 294 | // Your code that might throw 295 | } catch (error) { 296 | // TypeScript types catch blocks as 'unknown' 297 | if (isError(error)) { 298 | console.error(error.message); 299 | console.error(error.stack); 300 | } 301 | } 302 | ``` 303 | 304 | ## License 305 | 306 | MIT 307 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | To report a vulnerability either create an issue on GitHub or send an email to nhirschfeld@gmail.com 6 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { fileURLToPath } from 'node:url'; 3 | import { fixupPluginRules } from '@eslint/compat'; 4 | import eslintJS from '@eslint/js'; 5 | import eslintPluginNode from 'eslint-plugin-n'; 6 | import eslintPluginPerfectionist from 'eslint-plugin-perfectionist'; 7 | import eslintPluginPromise from 'eslint-plugin-promise'; 8 | import eslintPluginUnicorn from 'eslint-plugin-unicorn'; 9 | import eslintPluginUnusedImports from 'eslint-plugin-unused-imports'; 10 | import eslintPluginVitest from 'eslint-plugin-vitest'; 11 | import eslintPluginTSDoc from 'eslint-plugin-tsdoc'; 12 | import globals from 'globals'; 13 | import eslintTS from 'typescript-eslint'; 14 | 15 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 16 | 17 | export default eslintTS.config( 18 | eslintJS.configs.recommended, 19 | ...eslintTS.configs.strictTypeChecked, 20 | ...eslintTS.configs.stylisticTypeChecked, 21 | eslintPluginNode.configs['flat/recommended-module'], 22 | eslintPluginPromise.configs['flat/recommended'], 23 | eslintPluginUnicorn.configs.recommended, 24 | eslintPluginPerfectionist.configs['recommended-alphabetical'], 25 | { 26 | languageOptions: { 27 | globals: { 28 | ...globals.node, 29 | }, 30 | parserOptions: { 31 | projectService: true, 32 | tsconfigRootDir: __dirname, 33 | }, 34 | }, 35 | plugins: { 36 | 'tsdoc': fixupPluginRules(eslintPluginTSDoc), 37 | 'unused-imports': eslintPluginUnusedImports, 38 | }, 39 | rules: { 40 | '@typescript-eslint/array-type': ['error', { default: 'array' }], 41 | '@typescript-eslint/consistent-indexed-object-style': 'error', 42 | '@typescript-eslint/consistent-type-definitions': 'warn', 43 | '@typescript-eslint/naming-convention': [ 44 | 'error', 45 | { 46 | custom: { 47 | match: false, 48 | regex: '^[IT][A-Z]', 49 | }, 50 | format: ['PascalCase'], 51 | selector: 'interface', 52 | }, 53 | { 54 | custom: { 55 | match: false, 56 | regex: '^[IT][A-Z]', 57 | }, 58 | format: ['PascalCase'], 59 | selector: 'typeAlias', 60 | }, 61 | { 62 | format: ['PascalCase'], 63 | selector: 'enumMember', 64 | }, 65 | { 66 | custom: { 67 | match: true, 68 | regex: '^[A-Z]$', 69 | }, 70 | format: ['PascalCase'], 71 | selector: 'typeParameter', 72 | }, 73 | ], 74 | '@typescript-eslint/no-extra-non-null-assertion': 'error', 75 | '@typescript-eslint/no-floating-promises': [ 76 | 'error', 77 | { ignoreIIFE: true, ignoreVoid: true }, 78 | ], 79 | '@typescript-eslint/no-for-in-array': 'error', 80 | '@typescript-eslint/no-inferrable-types': 'error', 81 | '@typescript-eslint/no-non-null-assertion': 'off', 82 | '@typescript-eslint/no-redundant-type-constituents': 'warn', 83 | '@typescript-eslint/no-require-imports': 'warn', 84 | '@typescript-eslint/no-this-alias': 'error', 85 | '@typescript-eslint/no-unnecessary-boolean-literal-compare': 86 | 'error', 87 | '@typescript-eslint/no-unnecessary-condition': 'error', 88 | '@typescript-eslint/no-unnecessary-qualifier': 'warn', 89 | '@typescript-eslint/no-unnecessary-type-arguments': 'error', 90 | '@typescript-eslint/no-unused-expressions': 'warn', 91 | '@typescript-eslint/no-unused-vars': [ 92 | 'warn', 93 | { args: 'all', argsIgnorePattern: '^_' }, 94 | ], 95 | '@typescript-eslint/no-useless-constructor': 'warn', 96 | '@typescript-eslint/no-useless-empty-export': 'warn', 97 | '@typescript-eslint/prefer-as-const': 'warn', 98 | '@typescript-eslint/prefer-for-of': 'warn', 99 | '@typescript-eslint/prefer-includes': 'warn', 100 | '@typescript-eslint/prefer-nullish-coalescing': 'error', 101 | '@typescript-eslint/prefer-optional-chain': 'error', 102 | '@typescript-eslint/require-await': 'error', 103 | '@typescript-eslint/restrict-template-expressions': 'off', 104 | '@typescript-eslint/switch-exhaustiveness-check': 'warn', 105 | 'curly': 'error', 106 | 'eqeqeq': 'error', 107 | 'n/no-extraneous-import': 'off', 108 | 'n/no-missing-import': 'off', 109 | 'n/no-process-exit': 'error', 110 | 'n/no-unsupported-features/node-builtins': 'off', 111 | 'no-console': 'warn', 112 | 'no-unused-vars': 'off', 113 | 'object-shorthand': 'error', 114 | 'perfectionist/sort-exports': [ 115 | 'error', 116 | { 117 | order: 'asc', 118 | type: 'natural', 119 | }, 120 | ], 121 | 'perfectionist/sort-imports': 'off', 122 | 'perfectionist/sort-named-imports': [ 123 | 'error', 124 | { 125 | order: 'asc', 126 | type: 'natural', 127 | }, 128 | ], 129 | 'prefer-const': ['error', { destructuring: 'all' }], 130 | 'prefer-destructuring': 'error', 131 | 'prefer-template': 'warn', 132 | 'tsdoc/syntax': 0, 133 | 'unicorn/catch-error-name': 'off', 134 | 'unicorn/explicit-length-check': 'off', 135 | 'unicorn/filename-case': 'off', 136 | 'unicorn/new-for-builtins': 'off', 137 | 'unicorn/no-array-callback-reference': 'off', 138 | 'unicorn/no-array-for-each': 'off', 139 | 'unicorn/no-array-reduce': 'off', 140 | 'unicorn/no-nested-ternary': 'off', 141 | 'unicorn/no-null': 'off', 142 | 'unicorn/no-process-exit': 'off', 143 | 'unicorn/no-useless-undefined': 'off', 144 | 'unicorn/prefer-module': 'off', 145 | 'unicorn/prefer-string-raw': 'off', 146 | 'unicorn/prevent-abbreviations': 'off', 147 | 'unused-imports/no-unused-imports': 'error', 148 | }, 149 | }, 150 | { 151 | extends: [eslintTS.configs.disableTypeChecked], 152 | files: ['**/*.js', '**/*.cjs', '**/*.mjs', 'eslint.config.mjs'], 153 | }, 154 | { 155 | files: ['**/*.spec.{ts,tsx}'], 156 | plugins: { 157 | vitest: eslintPluginVitest, 158 | }, 159 | rules: { 160 | ...eslintPluginVitest.configs.recommended.rules, 161 | '@typescript-eslint/ban-ts-comment': 'off', 162 | '@typescript-eslint/no-confusing-void-expression': 'off', 163 | '@typescript-eslint/no-empty-function': 'off', 164 | '@typescript-eslint/no-explicit-any': 'off', 165 | '@typescript-eslint/no-floating-promises': 'off', 166 | '@typescript-eslint/no-implied-eval': 'off', 167 | '@typescript-eslint/no-magic-numbers': 'off', 168 | '@typescript-eslint/no-misused-promises': [ 169 | 'error', 170 | { 171 | checksVoidReturn: false, 172 | }, 173 | ], 174 | '@typescript-eslint/no-unsafe-argument': 'off', 175 | '@typescript-eslint/no-unsafe-assignment': 'off', 176 | '@typescript-eslint/no-unsafe-call': 'off', 177 | '@typescript-eslint/no-unsafe-member-access': 'off', 178 | '@typescript-eslint/no-unsafe-return': 'off', 179 | '@typescript-eslint/no-var-requires': 'off', 180 | '@typescript-eslint/prefer-as-const': 'off', 181 | '@typescript-eslint/require-await': 'off', 182 | '@typescript-eslint/restrict-template-expressions': 'off', 183 | '@typescript-eslint/unbound-method': 'off', 184 | 'import-x/no-named-as-default': 'off', 185 | 'import-x/no-named-as-default-member': 'off', 186 | 'prefer-rest-params': 'off', 187 | 'react-perf/jsx-no-new-array-as-prop': 'off', 188 | 'unicorn/consistent-function-scoping': 'off', 189 | 'unicorn/error-message': 'off', 190 | 'unicorn/no-await-expression-member': 'off', 191 | }, 192 | }, 193 | { 194 | ignores: ['out', 'dist', 'node_modules', 'target', 'coverage'], 195 | }, 196 | ); 197 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tool-belt/type-predicates", 3 | "version": "1.4.0", 4 | "description": "A comprehensive collection of performant type guards and assertions with excellent TypeScript support", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/Goldziher/type-predicates.git" 8 | }, 9 | "keywords": [ 10 | "assertions", 11 | "guards", 12 | "predicates", 13 | "runtime-checks", 14 | "type-assertions", 15 | "type-guards", 16 | "type-predicates", 17 | "type-safety", 18 | "typechecking", 19 | "typescript", 20 | "utilities", 21 | "utils", 22 | "validation" 23 | ], 24 | "author": "Na'aman Hirschfeld", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/Goldziher/type-predicates/issues" 28 | }, 29 | "homepage": "https://github.com/Goldziher/type-predicates#readme", 30 | "files": [ 31 | "dist", 32 | "LICENSE", 33 | "README.md" 34 | ], 35 | "main": "dist/index.js", 36 | "module": "dist/index.mjs", 37 | "types": "dist/index.d.ts", 38 | "exports": { 39 | ".": { 40 | "types": "./dist/index.d.ts", 41 | "import": "./dist/index.mjs", 42 | "require": "./dist/index.js", 43 | "default": "./dist/index.mjs" 44 | } 45 | }, 46 | "sideEffects": false, 47 | "scripts": { 48 | "prepublishOnly": "pnpm run build", 49 | "build": "rimraf dist && vite build", 50 | "format": "prettier --write .", 51 | "lint": "eslint --fix .", 52 | "prepare": "husky", 53 | "typecheck": "tsc --noEmit", 54 | "test": "vitest run", 55 | "test:coverage": "vitest run --coverage", 56 | "test:watch": "vitest" 57 | }, 58 | "devDependencies": { 59 | "@commitlint/cli": "^19.8.1", 60 | "@commitlint/config-conventional": "^19.8.1", 61 | "@eslint/compat": "^1.2.9", 62 | "@eslint/js": "^9.27.0", 63 | "@types/node": "^22.15.21", 64 | "@vitest/coverage-v8": "^3.1.4", 65 | "eslint": "^9.27.0", 66 | "eslint-plugin-n": "17.18.0", 67 | "eslint-plugin-perfectionist": "^4.13.0", 68 | "eslint-plugin-promise": "7.2.1", 69 | "eslint-plugin-tsdoc": "^0.4.0", 70 | "eslint-plugin-unicorn": "59.0.1", 71 | "eslint-plugin-unused-imports": "^4.1.4", 72 | "eslint-plugin-vitest": "^0.5.4", 73 | "expect-type": "^1.2.1", 74 | "globals": "^16.1.0", 75 | "husky": "^9.1.7", 76 | "lint-staged": "^16.0.0", 77 | "prettier": "^3.5.3", 78 | "prettier-plugin-jsdoc": "^1.3.2", 79 | "rimraf": "^6.0.1", 80 | "type-fest": "^4.41.0", 81 | "typescript": "^5.8.3", 82 | "typescript-eslint": "^8.32.1", 83 | "vite": "^6.3.5", 84 | "vite-plugin-dts": "^4.5.4", 85 | "vitest": "^3.1.4" 86 | }, 87 | "lint-staged": { 88 | "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,json,md,mdx,yaml,yml}": [ 89 | "prettier --write" 90 | ], 91 | "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": [ 92 | "eslint --fix" 93 | ] 94 | }, 95 | "engines": { 96 | "node": ">=18.0.0" 97 | }, 98 | "publishConfig": { 99 | "access": "public" 100 | }, 101 | "packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977" 102 | } 103 | -------------------------------------------------------------------------------- /src/assertions/assertIsAnyArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isAnyArrayBuffer } from '../guards/isAnyArrayBuffer'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsAnyArrayBuffer( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is ArrayBuffer | SharedArrayBuffer { 12 | if (!isAnyArrayBuffer(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsArgumentsObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isArgumentsObject } from '../guards/isArgumentsObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsArgumentsObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is IArguments { 12 | if (!isArgumentsObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsArray.ts: -------------------------------------------------------------------------------- 1 | import { ErrorMessage, ValueValidator } from '../types'; 2 | 3 | /** 4 | * @category Type Assertion 5 | * @example 6 | * 7 | * ```typescript 8 | * // doesn't throw, value is typed as unknown[] 9 | * assertIsArray(['xyz']); 10 | * 11 | * // doesn't throw, value is typed as string[] 12 | * assertIsArray(['xyz'], { valueValidator: isString }); 13 | * 14 | * // throws 15 | * assertIsArray(['xyz', 1], { valueValidator: isString }); 16 | * ``` 17 | * 18 | * @throws TypeError 19 | */ 20 | export function assertIsArray( 21 | input: unknown, 22 | options?: ErrorMessage, 23 | ): asserts input is unknown[]; 24 | 25 | export function assertIsArray( 26 | input: unknown, 27 | options: (ErrorMessage & ValueValidator) | ValueValidator, 28 | ): asserts input is T[]; 29 | 30 | export function assertIsArray( 31 | input: unknown, 32 | options?: Partial, 33 | ): asserts input is T[] { 34 | if (!Array.isArray(input)) { 35 | throw new TypeError(options?.message); 36 | } 37 | 38 | if (options?.valueValidator && !input.every(options.valueValidator)) { 39 | throw new TypeError(options.message); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/assertions/assertIsArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isArrayBuffer } from '../guards/isArrayBuffer'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsArrayBuffer( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is ArrayBuffer { 12 | if (!isArrayBuffer(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsArrayBufferView.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isArrayBufferView } from '../guards/isArrayBufferView'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsArrayBufferView( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is ArrayBufferView { 12 | if (!isArrayBufferView(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsAsyncFunction.ts: -------------------------------------------------------------------------------- 1 | import { AsyncFunction, isAsyncFunction } from '../guards/isAsyncFunction'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion works only in ES2018 and above 7 | * @category Type Assertion 8 | * @throws TypeError 9 | */ 10 | export function assertIsAsyncFunction( 11 | input: unknown, 12 | options?: ErrorMessage, 13 | ): asserts input is AsyncFunction { 14 | if (!isAsyncFunction(input)) { 15 | throw new TypeError(options?.message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/assertions/assertIsAsyncGenerator.ts: -------------------------------------------------------------------------------- 1 | import { isAsyncGenerator } from '../guards/isAsyncGenerator'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion works only in ES2018 and above 7 | * @category Type Assertion 8 | * @throws TypeError 9 | */ 10 | export function assertIsAsyncGenerator( 11 | input: unknown, 12 | options?: ErrorMessage, 13 | ): asserts input is AsyncGenerator { 14 | if (!isAsyncGenerator(input)) { 15 | throw new TypeError(options?.message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/assertions/assertIsAsyncGeneratorFunction.ts: -------------------------------------------------------------------------------- 1 | import { 2 | isAsyncGeneratorFunction, 3 | TypedAsyncGeneratorFunction, 4 | } from '../guards/isAsyncGeneratorFunction'; 5 | import { ErrorMessage } from '../types'; 6 | 7 | /** 8 | * @category Type Assertion 9 | * @throws TypeError 10 | */ 11 | export function assertIsAsyncGeneratorFunction< 12 | Y = unknown, 13 | R = unknown, 14 | N = unknown, 15 | >( 16 | input: unknown, 17 | options?: ErrorMessage, 18 | ): asserts input is TypedAsyncGeneratorFunction { 19 | if (!isAsyncGeneratorFunction(input)) { 20 | throw new TypeError(options?.message); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/assertions/assertIsAsyncIterable.ts: -------------------------------------------------------------------------------- 1 | import { isAsyncIterable } from '../guards/isAsyncIterable'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This guard tests for Symbol.asyncIterator. See: 7 | * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator} 8 | * @category Type Assertion 9 | * @throws TypeError 10 | */ 11 | export function assertIsAsyncIterable( 12 | input: unknown, 13 | options?: ErrorMessage, 14 | ): asserts input is AsyncIterable { 15 | if (!isAsyncIterable(input)) { 16 | throw new TypeError(options?.message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/assertions/assertIsBigInt.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isBigInt } from '../guards/isBigInt'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // does not throw 10 | * assertIsBigInt(BigInt(9007199254740991)); 11 | * 12 | * // throws 13 | * assertIsBigInt(9007199254740991n); 14 | * ``` 15 | * 16 | * @throws TypeError 17 | */ 18 | export function assertIsBigInt( 19 | input: unknown, 20 | options?: ErrorMessage, 21 | ): asserts input is bigint { 22 | if (!isBigInt(input)) { 23 | throw new TypeError(options?.message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/assertions/assertIsBigIntObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isBigIntObject } from '../guards/isBigIntObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsBigIntObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is bigint { 12 | if (!isBigIntObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsBoolean.ts: -------------------------------------------------------------------------------- 1 | import { isBoolean } from '../guards/isBoolean'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsBoolean( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is boolean { 12 | if (!isBoolean(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsBooleanObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isBooleanObject } from '../guards/isBooleanObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsBooleanObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is boolean { 12 | if (!isBooleanObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsBoxedPrimitive.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isBoxedPrimitive } from '../guards/isBoxedPrimitive'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsBoxedPrimitive( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is bigint | boolean | number | string | symbol { 12 | if (!isBoxedPrimitive(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsBuffer.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isBuffer } from '../guards/isBuffer'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsBuffer( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is Buffer { 12 | if (!isBuffer(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsDataView.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isDataView } from '../guards/isDataView'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsDataView( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is DataView { 12 | if (!isDataView(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsDate.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isDate } from '../guards/isDate'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsDate( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is Date { 12 | if (!isDate(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsDefined.ts: -------------------------------------------------------------------------------- 1 | import { isUndefined } from '../guards/isUndefined'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion asserts that the value is not null, use assertIsNotNullish to 7 | * also exclude undefined 8 | * @category Type Assertion 9 | * @throws TypeError 10 | */ 11 | export function assertIsDefined( 12 | input: T | undefined, 13 | options?: ErrorMessage, 14 | ): asserts input is T { 15 | if (isUndefined(input)) { 16 | throw new TypeError(options?.message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/assertions/assertIsEmptyArray.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isEmptyArray } from '../guards/isEmptyArray'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsEmptyArray( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is [] { 12 | if (!isEmptyArray(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsEmptyObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isEmptyObject } from '../guards/isEmptyObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsEmptyObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is Record { 12 | if (!isEmptyObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsEmptyString.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isEmptyString } from '../guards/isEmptyString'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsEmptyString( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is '' { 12 | if (!isEmptyString(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsError.ts: -------------------------------------------------------------------------------- 1 | import { isError } from '../guards/isError'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * ```typescript 6 | * // does not throw, value is typed as Error 7 | * assertIsError(new Error()); 8 | * 9 | * // does not throw, value is typed as Error 10 | * // Use type assertion for specific error types 11 | * const error = new TypeError(); 12 | * assertIsError(error); 13 | * const typeError = error as TypeError; 14 | * 15 | * // For custom errors, use type assertion after the check 16 | * class MyError extends Error {} 17 | * const myError = new MyError(); 18 | * assertIsError(myError); 19 | * const typedError = myError as MyError; 20 | * ``` 21 | * 22 | * /** 23 | * 24 | * @category Type Assertion 25 | * @example 26 | * 27 | * ```typescript 28 | * // does not throw, value is typed as Error 29 | * assertIsError(new Error()); 30 | * 31 | * // does not throw, value is typed as Error 32 | * // Use type assertion for specific error types 33 | * const error = new TypeError(); 34 | * assertIsError(error); 35 | * const typeError = error as TypeError; 36 | * 37 | * // For custom errors, use type assertion after the check 38 | * class MyError extends Error {} 39 | * const myError = new MyError(); 40 | * assertIsError(myError); 41 | * const typedError = myError as MyError; 42 | * ``` 43 | * 44 | * @throws {TypeError} Will throw an error if the input is not an Error object 45 | */ 46 | export function assertIsError( 47 | input: unknown, 48 | options?: ErrorMessage, 49 | ): asserts input is Error { 50 | if (!isError(input)) { 51 | throw new TypeError(options?.message); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/assertions/assertIsFinite.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isFinite } from '../guards/isFinite'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsFinite( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is number { 12 | if (!isFinite(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsFunction.ts: -------------------------------------------------------------------------------- 1 | import { isFunction } from '../guards/isFunction'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This guard works only in ES2018 and above 7 | * @category Type Assertion 8 | * @example 9 | * 10 | * ```typescript 11 | * // does not throw, value is typed as (...args: unknown[]) => unknown 12 | * assertIsFunction(() => true); 13 | * 14 | * // Use type assertion for specific function types 15 | * const myFunc = (x: number): string => x.toString(); 16 | * assertIsFunction(myFunc); 17 | * const typedFunc = myFunc as (x: number) => string; 18 | * 19 | * // throws - use isAsyncFunction for async functions 20 | * assertIsFunction(async () => Promise.resolve(null)); 21 | * 22 | * // throws - use isGeneratorFunction for generator functions 23 | * assertIsFunction(function* () {}); 24 | * 25 | * // throws - use isAsyncGeneratorFunction for async generator functions 26 | * assertIsFunction(async function* () {}); 27 | * 28 | * // throws - use isConstructor for class constructors 29 | * assertIsFunction(MyClass); 30 | * ``` 31 | * 32 | * @throws {TypeError} Will throw an error if the input is not a function 33 | */ 34 | export function assertIsFunction( 35 | input: unknown, 36 | options?: ErrorMessage, 37 | ): asserts input is (...args: unknown[]) => unknown { 38 | if (!isFunction(input)) { 39 | throw new TypeError(options?.message); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/assertions/assertIsGenerator.ts: -------------------------------------------------------------------------------- 1 | import { isGenerator } from '../guards/isGenerator'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion works only in ES2018 and above 7 | * @category Type Assertion 8 | * @throws TypeError 9 | */ 10 | export function assertIsGenerator( 11 | input: unknown, 12 | options?: ErrorMessage, 13 | ): asserts input is Generator { 14 | if (!isGenerator(input)) { 15 | throw new TypeError(options?.message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/assertions/assertIsGeneratorFunction.ts: -------------------------------------------------------------------------------- 1 | import { isGeneratorFunction } from '../guards/isGeneratorFunction'; 2 | import { ErrorMessage, TypedGeneratorFunction } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion works only in ES2018 and above 7 | * @category Type Assertion 8 | * @throws TypeError 9 | */ 10 | export function assertIsGeneratorFunction< 11 | Y = unknown, 12 | R = unknown, 13 | N = unknown, 14 | >( 15 | input: unknown, 16 | options?: ErrorMessage, 17 | ): asserts input is TypedGeneratorFunction { 18 | if (!isGeneratorFunction(input)) { 19 | throw new TypeError(options?.message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/assertions/assertIsInteger.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isInteger } from '../guards/isInteger'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsInteger( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is number { 12 | if (!isInteger(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsIterable.ts: -------------------------------------------------------------------------------- 1 | import { isIterable } from '../guards/isIterable'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This guard tests for Symbol.iterator, which defines the Iterable protocol. 7 | * See: 8 | * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols} 9 | * @category Type Assertion 10 | * @throws TypeError 11 | */ 12 | export function assertIsIterable( 13 | input: unknown, 14 | options?: ErrorMessage, 15 | ): asserts input is Iterable { 16 | if (!isIterable(input)) { 17 | throw new TypeError(options?.message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/assertions/assertIsIterator.ts: -------------------------------------------------------------------------------- 1 | import { isIterator } from '../guards/isIterator'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion works only in ES2018 and above 7 | * @category Type Assertion 8 | * @throws TypeError 9 | */ 10 | export function assertIsIterator( 11 | input: unknown, 12 | options?: ErrorMessage, 13 | ): asserts input is Iterator { 14 | if (!isIterator(input)) { 15 | throw new TypeError(options?.message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/assertions/assertIsMap.ts: -------------------------------------------------------------------------------- 1 | import { isMap } from '../guards/isMap'; 2 | import { ErrorMessage, KeyValidator, ValueValidator } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // does not throw, value is typed as Map 10 | * assertIsMap(new Map([['xyz', 'abc']])); 11 | * 12 | * // does not throw, value is typed as Map 13 | * assertIsMap( 14 | * new Map([ 15 | * ['abc', 'def'], 16 | * ['xyz', 100], 17 | * ]), 18 | * { 19 | * keyValidator: isString, 20 | * valueValidator: isUnion(isString, isNumber), 21 | * }, 22 | * ); 23 | * ``` 24 | * 25 | * @throws TypeError 26 | */ 27 | export function assertIsMap( 28 | input: unknown, 29 | options?: ErrorMessage, 30 | ): asserts input is Map; 31 | 32 | export function assertIsMap( 33 | input: unknown, 34 | options: (ErrorMessage & KeyValidator) | KeyValidator, 35 | ): asserts input is Map; 36 | 37 | export function assertIsMap( 38 | input: unknown, 39 | options: (ErrorMessage & ValueValidator) | ValueValidator, 40 | ): asserts input is Map; 41 | 42 | export function assertIsMap( 43 | input: unknown, 44 | options: 45 | | (ErrorMessage & KeyValidator & ValueValidator) 46 | | (KeyValidator & ValueValidator), 47 | ): asserts input is Map; 48 | 49 | export function assertIsMap( 50 | input: unknown, 51 | options?: Partial, 52 | ): asserts input is Map { 53 | if (!isMap(input)) { 54 | throw new TypeError(options?.message); 55 | } 56 | 57 | if (options?.keyValidator) { 58 | const keys = [...input.keys()]; 59 | if (!keys.every(options.keyValidator)) { 60 | throw new TypeError(options.message); 61 | } 62 | } 63 | 64 | if (options?.valueValidator) { 65 | const values = [...input.values()]; 66 | if (!values.every(options.valueValidator)) { 67 | throw new TypeError(options.message); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/assertions/assertIsMapIterator.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isMapIterator } from '../guards/isMapIterator'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsMapIterator( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is IterableIterator<[unknown, unknown]> { 12 | if (!isMapIterator(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNaN.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNaN } from '../guards/isNaN'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsNaN( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is number { 12 | if (!isNaN(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNativeError.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNativeError } from '../guards/isNativeError'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsNativeError( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is Error { 12 | if (!isNativeError(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNonEmptyArray.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNonEmptyArray } from '../guards/isNonEmptyArray'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsNonEmptyArray( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is [unknown, ...unknown[]] { 12 | if (!isNonEmptyArray(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNonEmptyString.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNonEmptyString } from '../guards/isNonEmptyString'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsNonEmptyString( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is string { 12 | if (!isNonEmptyString(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNotNull.ts: -------------------------------------------------------------------------------- 1 | import { isNull } from '../guards/isNull'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * This assertion asserts that the value is not null, use assertIsNotNullish to 7 | * also exclude undefined 8 | * @category Type Assertion 9 | * @throws TypeError 10 | */ 11 | export function assertIsNotNull( 12 | input: null | T, 13 | options?: ErrorMessage, 14 | ): asserts input is T { 15 | if (isNull(input)) { 16 | throw new TypeError(options?.message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/assertions/assertIsNotNullish.ts: -------------------------------------------------------------------------------- 1 | import { isNull } from '../guards/isNull'; 2 | import { isUndefined } from '../guards/isUndefined'; 3 | import { ErrorMessage } from '../types'; 4 | 5 | /** 6 | * @remarks 7 | * Tests false for undefined and null, true for all other values 8 | * @category Type Assertion 9 | * @throws TypeError 10 | */ 11 | export function assertIsNotNullish( 12 | input: null | T | undefined, 13 | options?: ErrorMessage, 14 | ): asserts input is T { 15 | if (isUndefined(input) || isNull(input)) { 16 | throw new TypeError(options?.message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/assertions/assertIsNull.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNull } from '../guards/isNull'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsNull( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is null { 12 | if (!isNull(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNullish.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNullish } from '../guards/isNullish'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsNullish( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is null | undefined { 12 | if (!isNullish(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsNumber.ts: -------------------------------------------------------------------------------- 1 | import { isNumber } from '../guards/isNumber'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // does not throw 10 | * assertIsNumber(1); 11 | * 12 | * // throws 13 | * assertIsNumber(new Number(1)); 14 | * ``` 15 | * 16 | * @throws TypeError 17 | */ 18 | export function assertIsNumber( 19 | input: unknown, 20 | options?: ErrorMessage, 21 | ): asserts input is number { 22 | if (!isNumber(input)) { 23 | throw new TypeError(options?.message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/assertions/assertIsNumberObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isNumberObject } from '../guards/isNumberObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // does not throw 10 | * assertIsNumberObject(new Number(1)); 11 | * 12 | * // throws 13 | * assertIsNumberObject(1); 14 | * ``` 15 | * 16 | * @throws TypeError 17 | */ 18 | export function assertIsNumberObject( 19 | input: unknown, 20 | options?: ErrorMessage, 21 | ): asserts input is number { 22 | if (!isNumberObject(input)) { 23 | throw new TypeError(options?.message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/assertions/assertIsObject.ts: -------------------------------------------------------------------------------- 1 | import { isObject } from '../guards/isObject'; 2 | import type { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * Tests true for all objects that have a typeof 'object' excluding null 7 | * @category Type Assertion 8 | * @example 9 | * 10 | * ```typescript 11 | * // does not throw, value is typed as object 12 | * assertIsObject({}); 13 | * 14 | * // does not throw, value is typed as object 15 | * assertIsObject([]); 16 | * 17 | * // throws 18 | * assertIsObject(null); 19 | * ``` 20 | * 21 | * @throws TypeError 22 | */ 23 | export function assertIsObject( 24 | input: unknown, 25 | options?: ErrorMessage, 26 | ): asserts input is object { 27 | if (!isObject(input)) { 28 | throw new TypeError(options?.message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/assertions/assertIsPlainObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isPlainObject } from '../guards/isPlainObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsPlainObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is Record { 12 | if (!isPlainObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsPromise.ts: -------------------------------------------------------------------------------- 1 | import { isPromise } from '../guards/isPromise'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @remarks 6 | * Works with custom promises as well, e.g. AxiosPromise or BlueBird 7 | * @category Type Assertion 8 | * @throws TypeError 9 | */ 10 | export function assertIsPromise( 11 | input: unknown, 12 | options?: ErrorMessage, 13 | ): asserts input is Promise { 14 | if (!isPromise(input)) { 15 | throw new TypeError(options?.message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/assertions/assertIsRecord.ts: -------------------------------------------------------------------------------- 1 | import { isRecord } from '../guards/isRecord'; 2 | import { ErrorMessage, KeyValidator, ValueValidator } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // does not throw, value is typed as Record 10 | * assertIsRecord({ key1: 'aaa', key2: 123 }); 11 | * 12 | * // does not throw, value is typed as Record 13 | * assertIsRecord( 14 | * { key1: 'aaa', key2: 123 }, 15 | * { 16 | * keyValidator: isString, 17 | * valueValidator: isUnion(isString, isNumber), 18 | * }, 19 | * ); 20 | * ``` 21 | * 22 | * @throws TypeError 23 | */ 24 | export function assertIsRecord( 25 | input: unknown, 26 | options?: ErrorMessage, 27 | ): asserts input is Record; 28 | export function assertIsRecord( 29 | input: unknown, 30 | options: (ErrorMessage & KeyValidator) | KeyValidator, 31 | ): asserts input is Record; 32 | export function assertIsRecord( 33 | input: unknown, 34 | options: (ErrorMessage & ValueValidator) | ValueValidator, 35 | ): asserts input is Record; 36 | export function assertIsRecord( 37 | input: unknown, 38 | options: 39 | | (ErrorMessage & KeyValidator & ValueValidator) 40 | | (KeyValidator & ValueValidator), 41 | ): asserts input is Record; 42 | export function assertIsRecord( 43 | input: unknown, 44 | options?: Partial, 45 | ): asserts input is Record { 46 | if (!isRecord(input)) { 47 | throw new TypeError(options?.message); 48 | } 49 | 50 | if (options?.keyValidator) { 51 | const keys = Object.keys(input); 52 | if (!keys.every(options.keyValidator)) { 53 | throw new TypeError(options.message); 54 | } 55 | } 56 | 57 | if (options?.valueValidator) { 58 | const values = Object.values(input); 59 | if (!values.every(options.valueValidator)) { 60 | throw new TypeError(options.message); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/assertions/assertIsRegExp.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isRegExp } from '../guards/isRegExp'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // does not throw 10 | * assertIsRegExp(new RegExp('abc')); 11 | * 12 | * // does not throw 13 | * assertIsRegExp(/'abc'/); 14 | * ``` 15 | * 16 | * @throws TypeError 17 | */ 18 | export function assertIsRegExp( 19 | input: unknown, 20 | options?: ErrorMessage, 21 | ): asserts input is RegExp { 22 | if (!isRegExp(input)) { 23 | throw new TypeError(options?.message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/assertions/assertIsSafeInteger.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isSafeInteger } from '../guards/isSafeInteger'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsSafeInteger( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is number { 12 | if (!isSafeInteger(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsSet.ts: -------------------------------------------------------------------------------- 1 | import { isSet } from '../guards/isSet'; 2 | import { ErrorMessage, ValueValidator } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @example 7 | * 8 | * ```typescript 9 | * // doesn't throw, value is typed as Set 10 | * assertIsSet(new Set(['xyz'])); 11 | * 12 | * // doesn't throw, value is typed as Set 13 | * assertIsSet(new Set(['xyz']), { valueValidator: isString }); 14 | * ``` 15 | * 16 | * @throws TypeError 17 | */ 18 | export function assertIsSet( 19 | input: unknown, 20 | options?: ErrorMessage, 21 | ): asserts input is Set; 22 | export function assertIsSet( 23 | input: unknown, 24 | options: (ErrorMessage & ValueValidator) | ValueValidator, 25 | ): asserts input is Set; 26 | export function assertIsSet( 27 | input: unknown, 28 | options?: Partial, 29 | ): asserts input is Set { 30 | if (!isSet(input)) { 31 | throw new TypeError(options?.message); 32 | } 33 | 34 | if (options?.valueValidator) { 35 | const values = [...input]; 36 | if (!values.every(options.valueValidator)) { 37 | throw new TypeError(options.message); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/assertions/assertIsSetIterator.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isSetIterator } from '../guards/isSetIterator'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsSetIterator( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is IterableIterator { 12 | if (!isSetIterator(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsSharedArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isSharedArrayBuffer } from '../guards/isSharedArrayBuffer'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsSharedArrayBuffer( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is SharedArrayBuffer { 12 | if (!isSharedArrayBuffer(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsString.ts: -------------------------------------------------------------------------------- 1 | import { isString } from '../guards/isString'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsString( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is string { 12 | if (!isString(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsStringObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isStringObject } from '../guards/isStringObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsStringObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is string { 12 | if (!isStringObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsSymbol.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isSymbol } from '../guards/isSymbol'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsSymbol( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is symbol { 12 | if (!isSymbol(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsSymbolObject.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isSymbolObject } from '../guards/isSymbolObject'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsSymbolObject( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is symbol { 12 | if (!isSymbolObject(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsTypedArray.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage, TypedArray } from '../types'; 2 | import { 3 | isBigInt64Array, 4 | isBigUint64Array, 5 | isFloat32Array, 6 | isFloat64Array, 7 | isInt8Array, 8 | isInt16Array, 9 | isInt32Array, 10 | isTypedArray, 11 | isUint8Array, 12 | isUint8ClampedArray, 13 | isUint16Array, 14 | isUint32Array, 15 | } from '../guards/isTypedArray'; 16 | 17 | /** 18 | * @category Type Assertion 19 | * @throws TypeError 20 | */ 21 | export function assertIsBigInt64Array( 22 | input: unknown, 23 | options?: ErrorMessage, 24 | ): asserts input is BigInt64Array { 25 | if (!isBigInt64Array(input)) { 26 | throw new TypeError(options?.message); 27 | } 28 | } 29 | 30 | /** 31 | * @category Type Assertion 32 | * @throws TypeError 33 | */ 34 | export function assertIsBigUint64Array( 35 | input: unknown, 36 | options?: ErrorMessage, 37 | ): asserts input is BigUint64Array { 38 | if (!isBigUint64Array(input)) { 39 | throw new TypeError(options?.message); 40 | } 41 | } 42 | 43 | /** 44 | * @category Type Assertion 45 | * @throws TypeError 46 | */ 47 | export function assertIsFloat32Array( 48 | input: unknown, 49 | options?: ErrorMessage, 50 | ): asserts input is Float32Array { 51 | if (!isFloat32Array(input)) { 52 | throw new TypeError(options?.message); 53 | } 54 | } 55 | 56 | /** 57 | * @category Type Assertion 58 | * @throws TypeError 59 | */ 60 | export function assertIsFloat64Array( 61 | input: unknown, 62 | options?: ErrorMessage, 63 | ): asserts input is Float64Array { 64 | if (!isFloat64Array(input)) { 65 | throw new TypeError(options?.message); 66 | } 67 | } 68 | 69 | /** 70 | * @category Type Assertion 71 | * @throws TypeError 72 | */ 73 | export function assertIsInt16Array( 74 | input: unknown, 75 | options?: ErrorMessage, 76 | ): asserts input is Int16Array { 77 | if (!isInt16Array(input)) { 78 | throw new TypeError(options?.message); 79 | } 80 | } 81 | 82 | /** 83 | * @category Type Assertion 84 | * @throws TypeError 85 | */ 86 | export function assertIsInt32Array( 87 | input: unknown, 88 | options?: ErrorMessage, 89 | ): asserts input is Int32Array { 90 | if (!isInt32Array(input)) { 91 | throw new TypeError(options?.message); 92 | } 93 | } 94 | 95 | /** 96 | * @category Type Assertion 97 | * @throws TypeError 98 | */ 99 | export function assertIsInt8Array( 100 | input: unknown, 101 | options?: ErrorMessage, 102 | ): asserts input is Int8Array { 103 | if (!isInt8Array(input)) { 104 | throw new TypeError(options?.message); 105 | } 106 | } 107 | 108 | /** 109 | * @category Type Assertion 110 | * @throws TypeError 111 | */ 112 | export function assertIsTypedArray( 113 | input: unknown, 114 | options?: ErrorMessage, 115 | ): asserts input is TypedArray { 116 | if (!isTypedArray(input)) { 117 | throw new TypeError(options?.message); 118 | } 119 | } 120 | 121 | /** 122 | * @category Type Assertion 123 | * @throws TypeError 124 | */ 125 | export function assertIsUint16Array( 126 | input: unknown, 127 | options?: ErrorMessage, 128 | ): asserts input is Uint16Array { 129 | if (!isUint16Array(input)) { 130 | throw new TypeError(options?.message); 131 | } 132 | } 133 | 134 | /** 135 | * @category Type Assertion 136 | * @throws TypeError 137 | */ 138 | export function assertIsUint32Array( 139 | input: unknown, 140 | options?: ErrorMessage, 141 | ): asserts input is Uint32Array { 142 | if (!isUint32Array(input)) { 143 | throw new TypeError(options?.message); 144 | } 145 | } 146 | 147 | /** 148 | * @category Type Assertion 149 | * @throws TypeError 150 | */ 151 | export function assertIsUint8Array( 152 | input: unknown, 153 | options?: ErrorMessage, 154 | ): asserts input is Uint8Array { 155 | if (!isUint8Array(input)) { 156 | throw new TypeError(options?.message); 157 | } 158 | } 159 | 160 | /** 161 | * @category Type Assertion 162 | * @throws TypeError 163 | */ 164 | export function assertIsUint8ClampedArray( 165 | input: unknown, 166 | options?: ErrorMessage, 167 | ): asserts input is Uint8ClampedArray { 168 | if (!isUint8ClampedArray(input)) { 169 | throw new TypeError(options?.message); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/assertions/assertIsUndefined.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorMessage } from '../types'; 2 | import { isUndefined } from '../guards/isUndefined'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsUndefined( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is undefined { 12 | if (!isUndefined(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsWeakMap.ts: -------------------------------------------------------------------------------- 1 | import { isWeakMap } from '../guards/isWeakMap'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsWeakMap( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is WeakMap { 12 | if (!isWeakMap(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/assertions/assertIsWeakSet.ts: -------------------------------------------------------------------------------- 1 | import { isWeakSet } from '../guards/isWeakSet'; 2 | import { ErrorMessage } from '../types'; 3 | 4 | /** 5 | * @category Type Assertion 6 | * @throws TypeError 7 | */ 8 | export function assertIsWeakSet( 9 | input: unknown, 10 | options?: ErrorMessage, 11 | ): asserts input is WeakSet { 12 | if (!isWeakSet(input)) { 13 | throw new TypeError(options?.message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/guards/isAnyArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | import { isUnion } from '../utils'; 2 | import { isArrayBuffer } from './isArrayBuffer'; 3 | import { isSharedArrayBuffer } from './isSharedArrayBuffer'; 4 | 5 | /** @category Type Guard */ 6 | export const isAnyArrayBuffer = isUnion( 7 | isArrayBuffer, 8 | isSharedArrayBuffer, 9 | ); 10 | -------------------------------------------------------------------------------- /src/guards/isArgumentsObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isArgumentsObject = createTypeGuard( 5 | (value) => 6 | typeof value === 'object' && 7 | value !== null && 8 | Object.prototype.toString.call(value) === '[object Arguments]', 9 | ); 10 | -------------------------------------------------------------------------------- /src/guards/isArray.ts: -------------------------------------------------------------------------------- 1 | import { ValueValidator } from '../types'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** 5 | * @category Type Guard 6 | * @example 7 | * 8 | * ```typescript 9 | * // true, typed as unknown[] 10 | * isArray(['xyz']); 11 | * 12 | * // true, typed as string[] 13 | * isArray(['xyz'], { valueValidator: isString }); 14 | * ``` 15 | */ 16 | export function isArray(input: unknown): input is unknown[]; 17 | export function isArray( 18 | input: unknown, 19 | options: ValueValidator, 20 | ): input is T[]; 21 | export function isArray( 22 | input: unknown, 23 | options?: ValueValidator, 24 | ): input is T[] { 25 | return createTypeGuard( 26 | (value) => 27 | Array.isArray(value) && 28 | (!options?.valueValidator || value.every(options.valueValidator)), 29 | )(input); 30 | } 31 | -------------------------------------------------------------------------------- /src/guards/isArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export const isArrayBuffer = createTypeGuard( 6 | (value) => 7 | isObject(value) && 8 | (toObjectString(value) === '[object ArrayBuffer]' || 9 | value instanceof ArrayBuffer), 10 | ); 11 | -------------------------------------------------------------------------------- /src/guards/isArrayBufferView.ts: -------------------------------------------------------------------------------- 1 | import { isTypedArray } from './isTypedArray'; 2 | import { isDataView } from './isDataView'; 3 | import { createTypeGuard } from '../utils'; 4 | 5 | /** @category Type Guard */ 6 | export const isArrayBufferView = createTypeGuard( 7 | (value) => isTypedArray(value) || isDataView(value), 8 | ); 9 | -------------------------------------------------------------------------------- /src/guards/isAsyncFunction.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | 3 | export type AsyncFunction = (...args: unknown[]) => Promise; 4 | 5 | /** 6 | * @remarks 7 | * This guard works only in ES2018 and above 8 | * @category Type Guard 9 | */ 10 | export function isAsyncFunction( 11 | input: unknown, 12 | ): input is AsyncFunction { 13 | return createTypeGuard>( 14 | (value) => 15 | typeof value === 'function' && 16 | toObjectString(value) === '[object AsyncFunction]', 17 | )(input); 18 | } 19 | -------------------------------------------------------------------------------- /src/guards/isAsyncGenerator.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @remarks 6 | * This guard works only in ES2018 and above 7 | * @category Type Guard 8 | */ 9 | export function isAsyncGenerator( 10 | input: unknown, 11 | ): input is AsyncGenerator { 12 | return createTypeGuard>( 13 | (value) => 14 | isObject(value) && 15 | toObjectString(value) === '[object AsyncGenerator]', 16 | )(input); 17 | } 18 | -------------------------------------------------------------------------------- /src/guards/isAsyncGeneratorFunction.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | 3 | export type TypedAsyncGeneratorFunction = ( 4 | ...args: unknown[] 5 | ) => AsyncGenerator; 6 | 7 | /** 8 | * @remarks 9 | * This guard works only in ES2018 and above 10 | * @category Type Guard 11 | */ 12 | export function isAsyncGeneratorFunction( 13 | input: unknown, 14 | ): input is TypedAsyncGeneratorFunction { 15 | return createTypeGuard>( 16 | (value) => 17 | typeof value === 'function' && 18 | toObjectString(value) === '[object AsyncGeneratorFunction]', 19 | )(input); 20 | } 21 | -------------------------------------------------------------------------------- /src/guards/isAsyncIterable.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @remarks 6 | * This guard tests for Symbol.asyncIterator. See: 7 | * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator} 8 | * @category Type Guard 9 | */ 10 | export function isAsyncIterable( 11 | input: unknown, 12 | ): input is AsyncIterable { 13 | return createTypeGuard>( 14 | (value) => 15 | isObject(value) && 16 | typeof Reflect.get(value, Symbol.asyncIterator) === 'function', 17 | )(input); 18 | } 19 | -------------------------------------------------------------------------------- /src/guards/isBigInt.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** 4 | * @category Type Guard 5 | * @example 6 | * 7 | * ```typescript 8 | * // true 9 | * isBigInt(BigInt(9007199254740991)); 10 | * 11 | * // true 12 | * isBigInt(9007199254740991n); 13 | * ``` 14 | */ 15 | export const isBigInt = createTypeGuard( 16 | (value) => typeof value === 'bigint', 17 | ); 18 | -------------------------------------------------------------------------------- /src/guards/isBigIntObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isBigIntObject = createTypeGuard( 5 | (value) => 6 | typeof value === 'object' && 7 | value !== null && 8 | Object.prototype.toString.call(value) === '[object BigInt]', 9 | ); 10 | -------------------------------------------------------------------------------- /src/guards/isBoolean.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** 4 | * @category Type Guard 5 | * @example 6 | * 7 | * ```typescript 8 | * // true 9 | * isBoolean(false); 10 | * 11 | * // false 12 | * isBoolean(new Boolean(false)); 13 | * ``` 14 | */ 15 | export const isBoolean = createTypeGuard( 16 | (value) => typeof value === 'boolean', 17 | ); 18 | -------------------------------------------------------------------------------- /src/guards/isBooleanObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @category Type Guard 6 | * @example 7 | * 8 | * ```typescript 9 | * // true 10 | * isBooleanObject(new Boolean(true)); 11 | * 12 | * // false 13 | * isBooleanObject(true); 14 | * ``` 15 | */ 16 | export const isBooleanObject = createTypeGuard( 17 | (value) => 18 | isObject(value) && 19 | toObjectString(value) === '[object Boolean]' && 20 | typeof value.valueOf() === 'boolean', 21 | ); 22 | -------------------------------------------------------------------------------- /src/guards/isBoxedPrimitive.ts: -------------------------------------------------------------------------------- 1 | import { isBooleanObject } from './isBooleanObject'; 2 | import { isNumberObject } from './isNumberObject'; 3 | import { isStringObject } from './isStringObject'; 4 | import { isBigIntObject } from './isBigIntObject'; 5 | import { isSymbolObject } from './isSymbolObject'; 6 | import { createTypeGuard } from '../utils'; 7 | 8 | /** @category Type Guard */ 9 | export const isBoxedPrimitive = createTypeGuard< 10 | bigint | boolean | number | string | symbol 11 | >( 12 | (value) => 13 | isBooleanObject(value) || 14 | isNumberObject(value) || 15 | isStringObject(value) || 16 | isBigIntObject(value) || 17 | isSymbolObject(value), 18 | ); 19 | -------------------------------------------------------------------------------- /src/guards/isBuffer.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isBuffer = createTypeGuard( 5 | (value) => typeof Buffer !== 'undefined' && value instanceof Buffer, 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isDataView.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export const isDataView = createTypeGuard( 6 | (value) => 7 | isObject(value) && 8 | (toObjectString(value) === '[object DataView]' || 9 | value instanceof DataView), 10 | ); 11 | -------------------------------------------------------------------------------- /src/guards/isDate.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export const isDate = createTypeGuard( 6 | (value) => 7 | isObject(value) && 8 | (toObjectString(value) === '[object Date]' || value instanceof Date), 9 | ); 10 | -------------------------------------------------------------------------------- /src/guards/isDefined.ts: -------------------------------------------------------------------------------- 1 | /** @category Type Guard */ 2 | export function isDefined(input: T | undefined): input is T { 3 | return input !== undefined; 4 | } 5 | -------------------------------------------------------------------------------- /src/guards/isEmptyArray.ts: -------------------------------------------------------------------------------- 1 | import { isArray } from './isArray'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export const isEmptyArray = createTypeGuard<[]>( 6 | (value) => isArray(value) && value.length === 0, 7 | ); 8 | -------------------------------------------------------------------------------- /src/guards/isEmptyObject.ts: -------------------------------------------------------------------------------- 1 | import { isObject } from './isObject'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export const isEmptyObject = createTypeGuard>( 6 | (value) => 7 | isObject(value) && 8 | !Array.isArray(value) && 9 | Object.keys(value).length === 0, 10 | ); 11 | -------------------------------------------------------------------------------- /src/guards/isEmptyString.ts: -------------------------------------------------------------------------------- 1 | import { isString } from './isString'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export const isEmptyString = createTypeGuard<''>( 6 | (value) => isString(value) && value.length === 0, 7 | ); 8 | -------------------------------------------------------------------------------- /src/guards/isError.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @category Type Guard 6 | * @example 7 | * 8 | * ```typescript 9 | * // true 10 | * isError(new Error()); 11 | * 12 | * // true, value is typed as Error 13 | * isError(new TypeError()); 14 | * 15 | * // true, value is still typed as Error (use type assertion if needed) 16 | * const error = new TypeError(); 17 | * if (isError(error)) { 18 | * // error is now typed as Error 19 | * } 20 | * 21 | * // For custom errors, you can use type assertion 22 | * class MyCustomError extends Error {} 23 | * const customError = new MyCustomError(); 24 | * if (isError(customError)) { 25 | * // customError is typed as Error 26 | * const myError = customError as MyCustomError; 27 | * } 28 | * ``` 29 | */ 30 | export function isError(input: unknown): input is Error { 31 | return createTypeGuard( 32 | (value) => 33 | isObject(value) && 34 | (toObjectString(value) === '[object Error]' || 35 | value instanceof Error), 36 | )(input); 37 | } 38 | -------------------------------------------------------------------------------- /src/guards/isFinite.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isFinite = createTypeGuard( 5 | (value) => typeof value === 'number' && Number.isFinite(value), 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isFunction.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | 3 | /** 4 | * @remarks 5 | * This guard works only in ES2018 and above 6 | * @category Type Guard 7 | * @example 8 | * 9 | * ```typescript 10 | * // true, value is typed as (...args: unknown[]) => unknown 11 | * isFunction(() => null); 12 | * 13 | * // false - use isAsyncFunction for async functions 14 | * isFunction(async () => Promise.resolve(null)); 15 | * 16 | * // false - use isGeneratorFunction for generator functions 17 | * isFunction(function* () {}); 18 | * 19 | * // false - use isAsyncGeneratorFunction for async generator functions 20 | * isFunction(async function* () {}); 21 | * 22 | * // false - use isConstructor for class constructors 23 | * isFunction(MyClass); 24 | * 25 | * // Type assertion can be used for specific function types 26 | * const specificFn = (x: number): string => x.toString(); 27 | * if (isFunction(specificFn)) { 28 | * // specificFn is now typed as (...args: unknown[]) => unknown 29 | * // Use type assertion if needed: (specificFn as (x: number) => string)(42); 30 | * } 31 | * ``` 32 | */ 33 | export function isFunction( 34 | input: unknown, 35 | ): input is (...args: unknown[]) => unknown { 36 | return createTypeGuard<(...args: unknown[]) => unknown>( 37 | (value) => 38 | typeof value === 'function' && 39 | toObjectString(value) === '[object Function]', 40 | )(input); 41 | } 42 | -------------------------------------------------------------------------------- /src/guards/isGenerator.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export function isGenerator( 6 | input: unknown, 7 | ): input is Generator { 8 | return createTypeGuard>( 9 | (value) => 10 | isObject(value) && toObjectString(value) === '[object Generator]', 11 | )(input); 12 | } 13 | -------------------------------------------------------------------------------- /src/guards/isGeneratorFunction.ts: -------------------------------------------------------------------------------- 1 | import { TypedGeneratorFunction } from '../types'; 2 | import { createTypeGuard, toObjectString } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export function isGeneratorFunction( 6 | input: unknown, 7 | ): input is TypedGeneratorFunction { 8 | return createTypeGuard>( 9 | (value) => 10 | typeof value === 'function' && 11 | toObjectString(value) === '[object GeneratorFunction]', 12 | )(input); 13 | } 14 | -------------------------------------------------------------------------------- /src/guards/isInteger.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isInteger = createTypeGuard( 5 | (value) => typeof value === 'number' && Number.isInteger(value), 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isIterable.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | import { isObject } from './isObject'; 3 | import { isString } from './isString'; 4 | 5 | /** 6 | * @remarks 7 | * This guard tests for Symbol.iterator, which defines the Iterable protocol. 8 | * See: 9 | * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols} 10 | * @category Type Guard 11 | */ 12 | export function isIterable(input: unknown): input is Iterable { 13 | return createTypeGuard>( 14 | (value) => 15 | (isObject(value) && 16 | typeof Reflect.get(value, Symbol.iterator) === 'function') || 17 | isString(value), 18 | )(input); 19 | } 20 | -------------------------------------------------------------------------------- /src/guards/isIterator.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @remarks 6 | * This guard tests for the presence of a '.next' method on the object, which 7 | * defines the Iteration protocol. See: 8 | * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols}. 9 | * 10 | * At present it is not possible to distinguish between Iterator and 11 | * AsyncIterator using reflection. 12 | * @category Type Guard 13 | */ 14 | export function isIterator( 15 | input: unknown, 16 | ): input is Iterator { 17 | return createTypeGuard>( 18 | (value) => 19 | isObject(value) && typeof Reflect.get(value, 'next') === 'function', 20 | )(input); 21 | } 22 | -------------------------------------------------------------------------------- /src/guards/isMap.ts: -------------------------------------------------------------------------------- 1 | import { KeyValidator, ValueValidator } from '../types'; 2 | import { createTypeGuard, toObjectString } from '../utils'; 3 | import { isObject } from './isObject'; 4 | 5 | /** 6 | * @category Type Guard 7 | * @example 8 | * 9 | * ```typescript 10 | * // true, value is typed as Map 11 | * isMap(new Map([['xyz', 'abc']])); 12 | * 13 | * // true, value is typed as Map 14 | * isMap( 15 | * new Map([ 16 | * ['abc', 'def'], 17 | * ['xyz', 100], 18 | * ]), 19 | * { 20 | * keyValidator: isString, 21 | * valueValidator: isUnion(isString, isNumber), 22 | * }, 23 | * ); 24 | * ``` 25 | */ 26 | export function isMap(input: unknown): input is Map; 27 | export function isMap( 28 | input: unknown, 29 | options: KeyValidator, 30 | ): input is Map; 31 | export function isMap( 32 | input: unknown, 33 | options: ValueValidator, 34 | ): input is Map; 35 | export function isMap( 36 | input: unknown, 37 | options: KeyValidator & ValueValidator, 38 | ): input is Map; 39 | export function isMap( 40 | input: unknown, 41 | options?: Partial, 42 | ): input is Map { 43 | return createTypeGuard< 44 | Map, 45 | Partial | undefined 46 | >((value) => { 47 | if ( 48 | !(value instanceof Map) && 49 | (!isObject(value) || toObjectString(value) !== '[object Map]') 50 | ) { 51 | return false; 52 | } 53 | 54 | const map = value as Map; 55 | 56 | if (options?.valueValidator) { 57 | for (const v of map.values()) { 58 | if (!options.valueValidator(v)) { 59 | return false; 60 | } 61 | } 62 | } 63 | 64 | if (options?.keyValidator) { 65 | for (const k of map.keys()) { 66 | if (!options.keyValidator(k)) { 67 | return false; 68 | } 69 | } 70 | } 71 | 72 | return true; 73 | })(input); 74 | } 75 | -------------------------------------------------------------------------------- /src/guards/isMapIterator.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isMapIterator = createTypeGuard< 5 | IterableIterator<[unknown, unknown]> 6 | >( 7 | (value) => 8 | typeof value === 'object' && 9 | value !== null && 10 | Object.prototype.toString.call(value) === '[object Map Iterator]', 11 | ); 12 | -------------------------------------------------------------------------------- /src/guards/isNaN.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isNaN = createTypeGuard( 5 | (value) => typeof value === 'number' && Number.isNaN(value), 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isNativeError.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isNativeError = createTypeGuard( 5 | (value) => 6 | value instanceof Error || 7 | value instanceof EvalError || 8 | value instanceof RangeError || 9 | value instanceof ReferenceError || 10 | value instanceof SyntaxError || 11 | value instanceof TypeError || 12 | value instanceof URIError || 13 | (typeof AggregateError !== 'undefined' && 14 | value instanceof AggregateError), 15 | ); 16 | -------------------------------------------------------------------------------- /src/guards/isNonEmptyArray.ts: -------------------------------------------------------------------------------- 1 | import { isArray } from './isArray'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export const isNonEmptyArray = createTypeGuard<[unknown, ...unknown[]]>( 6 | (value) => isArray(value) && value.length > 0, 7 | ); 8 | -------------------------------------------------------------------------------- /src/guards/isNonEmptyString.ts: -------------------------------------------------------------------------------- 1 | import { isString } from './isString'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export const isNonEmptyString = createTypeGuard( 6 | (value) => isString(value) && value.length > 0, 7 | ); 8 | -------------------------------------------------------------------------------- /src/guards/isNotNull.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @remarks 3 | * This guard checks that the value is not null, use isNotNullish to also 4 | * exclude undefined 5 | * @category Type Guard 6 | */ 7 | export function isNotNull(input: null | T): input is T { 8 | return input !== null; 9 | } 10 | -------------------------------------------------------------------------------- /src/guards/isNotNullish.ts: -------------------------------------------------------------------------------- 1 | import { isDefined } from './isDefined'; 2 | import { isNotNull } from './isNotNull'; 3 | 4 | /** 5 | * @remarks 6 | * Tests false for undefined and null, true for all other values 7 | * @category Type Guard 8 | */ 9 | export function isNotNullish( 10 | input: null | T | undefined, 11 | ): input is NonNullable { 12 | return isDefined(input) && isNotNull(input); 13 | } 14 | -------------------------------------------------------------------------------- /src/guards/isNull.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isNull = createTypeGuard((value) => value === null); 5 | -------------------------------------------------------------------------------- /src/guards/isNullish.ts: -------------------------------------------------------------------------------- 1 | import { isUnion } from '../utils'; 2 | import { isNull } from './isNull'; 3 | import { isUndefined } from './isUndefined'; 4 | 5 | /** 6 | * @remarks 7 | * Tests true for undefined and null, false for all other falsy values 8 | * @category Type Guard 9 | */ 10 | export const isNullish = isUnion(isNull, isUndefined); 11 | -------------------------------------------------------------------------------- /src/guards/isNumber.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** 4 | * @category Type Guard 5 | * @example 6 | * 7 | * ```typescript 8 | * // true 9 | * isNumber(1); 10 | * 11 | * // false 12 | * isNumber(new Number(1)); 13 | * 14 | * // false 15 | * isNumber(new BigInt(9007199254740991n)); 16 | * ``` 17 | */ 18 | export const isNumber = createTypeGuard( 19 | (value) => typeof value === 'number', 20 | ); 21 | -------------------------------------------------------------------------------- /src/guards/isNumberObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @category Type Guard 6 | * @example 7 | * 8 | * ```typescript 9 | * // true 10 | * isNumberObject(new Number(1)); 11 | * 12 | * // false 13 | * isNumberObject(1); 14 | * ``` 15 | */ 16 | export const isNumberObject = createTypeGuard( 17 | (value) => 18 | isObject(value) && 19 | toObjectString(value) === '[object Number]' && 20 | typeof value.valueOf() === 'number', 21 | ); 22 | -------------------------------------------------------------------------------- /src/guards/isObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** 4 | * @remarks 5 | * Tests true for all objects that have a typeof 'object' excluding null 6 | * @category Type Guard 7 | * @example 8 | * 9 | * ```typescript 10 | * // true 11 | * isObject({}); 12 | * 13 | * // true 14 | * isObject([]); 15 | * 16 | * // false 17 | * isObject(null); 18 | * ``` 19 | */ 20 | export const isObject = createTypeGuard( 21 | (value) => typeof value === 'object' && value !== null, 22 | ); 23 | -------------------------------------------------------------------------------- /src/guards/isPlainObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | function safeGetPrototypeOf(obj: unknown): null | object { 4 | try { 5 | const objAsObject = obj as object; 6 | 7 | const proto = Object.getPrototypeOf(objAsObject) as null | object; 8 | return proto; 9 | } catch { 10 | return null; 11 | } 12 | } 13 | 14 | /** 15 | * Checks if the value is a plain object (not a class instance) 16 | * 17 | * @category Type Guard 18 | * @example 19 | * 20 | * ```typescript 21 | * // true 22 | * isPlainObject({}); 23 | * isPlainObject({ a: 1 }); 24 | * isPlainObject(Object.create(null)); 25 | * isPlainObject(Object.create(Object.prototype)); 26 | * 27 | * // false 28 | * isPlainObject(new Date()); 29 | * isPlainObject([]); 30 | * isPlainObject(null); 31 | * isPlainObject(undefined); 32 | * ``` 33 | */ 34 | export const isPlainObject = createTypeGuard>( 35 | (value: unknown): value is Record => { 36 | if (value === null || typeof value !== 'object') { 37 | return false; 38 | } 39 | 40 | const proto = safeGetPrototypeOf(value); 41 | 42 | if (proto === null) { 43 | return true; 44 | } 45 | 46 | if (proto === Object.prototype) { 47 | return true; 48 | } 49 | 50 | const prototypeOfProto = safeGetPrototypeOf(proto); 51 | return prototypeOfProto === null; 52 | }, 53 | ); 54 | -------------------------------------------------------------------------------- /src/guards/isPromise.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @remarks 6 | * Works with custom promises as well, e.g. AxiosPromise or Bluebird 7 | * @category Type Guard 8 | */ 9 | export function isPromise(input: unknown): input is Promise { 10 | return createTypeGuard>( 11 | (value) => 12 | value instanceof Promise || 13 | (isObject(value) && 14 | typeof Reflect.get(value, 'then') === 'function'), 15 | )(input); 16 | } 17 | -------------------------------------------------------------------------------- /src/guards/isRecord.ts: -------------------------------------------------------------------------------- 1 | import { KeyValidator, ValueValidator } from '../types'; 2 | import { createTypeGuard, toObjectString } from '../utils'; 3 | import { isObject } from './isObject'; 4 | 5 | /** 6 | * @category Type Guard 7 | * @example 8 | * 9 | * ```typescript 10 | * * // true, value is typed as Record 11 | * isRecord( 12 | * { key1: 'aaa', key2: 123 }, 13 | * ); 14 | * 15 | * // true, value is typed as Record 16 | * isRecord( 17 | * { key1: 'aaa', key2: 123 }, 18 | * { 19 | * keyValidator: isString, 20 | * valueValidator: isUnion(isString, isNumber), 21 | * }, 22 | * ); 23 | * ``` 24 | */ 25 | export function isRecord( 26 | input: unknown, 27 | ): input is Record; 28 | export function isRecord( 29 | input: unknown, 30 | options: KeyValidator, 31 | ): input is Record; 32 | export function isRecord( 33 | input: unknown, 34 | options: ValueValidator, 35 | ): input is Record; 36 | export function isRecord( 37 | input: unknown, 38 | options: KeyValidator & ValueValidator, 39 | ): input is Record; 40 | export function isRecord( 41 | input: unknown, 42 | options?: Partial, 43 | ): input is Record { 44 | return createTypeGuard< 45 | Record, 46 | Partial | undefined 47 | >( 48 | (value) => 49 | isObject(value) && 50 | toObjectString(value) === '[object Object]' && 51 | (!options?.valueValidator || 52 | Object.values(value).every(options.valueValidator)) && 53 | (!options?.keyValidator || 54 | Object.keys(value).every(options.keyValidator)), 55 | )(input); 56 | } 57 | -------------------------------------------------------------------------------- /src/guards/isRegExp.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @category Type Guard 6 | * @example 7 | * 8 | * ```typescript 9 | * // true 10 | * isRegExp(new RegExp('somePattern')); 11 | * 12 | * // true 13 | * isRegExp(/somePattern/); 14 | * ``` 15 | */ 16 | export const isRegExp = createTypeGuard( 17 | (value) => 18 | isObject(value) && 19 | (toObjectString(value) === '[object RegExp]' || 20 | value instanceof RegExp), 21 | ); 22 | -------------------------------------------------------------------------------- /src/guards/isSafeInteger.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isSafeInteger = createTypeGuard( 5 | (value) => typeof value === 'number' && Number.isSafeInteger(value), 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isSet.ts: -------------------------------------------------------------------------------- 1 | import { ValueValidator } from '../types'; 2 | import { createTypeGuard, toObjectString } from '../utils'; 3 | import { isObject } from './isObject'; 4 | 5 | /** 6 | * ```typescript 7 | * // true, value is typed as Set 8 | * isSet(new Set(['xyz'])); 9 | * 10 | * // true, value is typed as Set 11 | * isSet(new Set(['xyz']), { valueValidator: isString }); 12 | * ``` 13 | * 14 | * /** 15 | * 16 | * @category Type Guard 17 | * @example 18 | * 19 | * ```typescript 20 | * // true, value is typed as Set 21 | * isSet(new Set(['xyz'])); 22 | * 23 | * // true, value is typed as Set 24 | * isSet(new Set(['xyz']), { valueValidator: isString }); 25 | * ``` 26 | */ 27 | export function isSet(input: unknown): input is Set; 28 | export function isSet( 29 | input: unknown, 30 | options: ValueValidator, 31 | ): input is Set; 32 | export function isSet( 33 | input: unknown, 34 | options?: ValueValidator, 35 | ): input is Set { 36 | return createTypeGuard, undefined | ValueValidator>((value) => { 37 | if ( 38 | !isObject(value) || 39 | (toObjectString(value) !== '[object Set]' && 40 | !(value instanceof Set)) 41 | ) { 42 | return false; 43 | } 44 | 45 | const set = value as Set; 46 | 47 | if (options?.valueValidator) { 48 | for (const item of set) { 49 | if (!options.valueValidator(item)) { 50 | return false; 51 | } 52 | } 53 | } 54 | 55 | return true; 56 | })(input); 57 | } 58 | -------------------------------------------------------------------------------- /src/guards/isSetIterator.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isSetIterator = createTypeGuard>( 5 | (value) => 6 | typeof value === 'object' && 7 | value !== null && 8 | Object.prototype.toString.call(value) === '[object Set Iterator]', 9 | ); 10 | -------------------------------------------------------------------------------- /src/guards/isSharedArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export const isSharedArrayBuffer = createTypeGuard( 6 | (value) => 7 | isObject(value) && 8 | (toObjectString(value) === '[object SharedArrayBuffer]' || 9 | value instanceof SharedArrayBuffer), 10 | ); 11 | -------------------------------------------------------------------------------- /src/guards/isString.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** 4 | * ```typescript 5 | * // true 6 | * isString('xyz'); 7 | * 8 | * // false 9 | * isString(new String('xyz')); 10 | * ``` 11 | * 12 | * /** 13 | * 14 | * @category Type Guard 15 | * @example 16 | * 17 | * ```typescript 18 | * // true 19 | * isString('xyz'); 20 | * 21 | * // false 22 | * isString(new String('xyz')); 23 | * ``` 24 | */ 25 | export const isString = createTypeGuard( 26 | (value) => typeof value === 'string', 27 | ); 28 | -------------------------------------------------------------------------------- /src/guards/isStringObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** 5 | * @category Type Guard 6 | * @example 7 | * 8 | * ```typescript 9 | * // true 10 | * isStringObject(new String('xyz')); 11 | * 12 | * // false 13 | * isStringObject('xyz'); 14 | * ``` 15 | */ 16 | export const isStringObject = createTypeGuard( 17 | (value) => 18 | isObject(value) && 19 | toObjectString(value) === '[object String]' && 20 | typeof value.valueOf() === 'string', 21 | ); 22 | -------------------------------------------------------------------------------- /src/guards/isSymbol.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isSymbol = createTypeGuard( 5 | (value) => typeof value === 'symbol', 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isSymbolObject.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isSymbolObject = createTypeGuard( 5 | (value) => 6 | typeof value === 'object' && 7 | value !== null && 8 | Object.prototype.toString.call(value) === '[object Symbol]', 9 | ); 10 | -------------------------------------------------------------------------------- /src/guards/isTypedArray.ts: -------------------------------------------------------------------------------- 1 | import { TypedArray } from '../types'; 2 | import { createTypeGuard } from '../utils'; 3 | 4 | /** @category Type Guard */ 5 | export const isTypedArray = createTypeGuard( 6 | (value) => 7 | value instanceof Object.getPrototypeOf(Int8Array) || 8 | value instanceof Object.getPrototypeOf(Uint8Array), 9 | ); 10 | 11 | /** @category Type Guard */ 12 | export const isInt8Array = (input: unknown): input is Int8Array => 13 | createTypeGuard( 14 | (value) => 15 | isTypedArray(value) && value[Symbol.toStringTag] === 'Int8Array', 16 | )(input); 17 | 18 | /** @category Type Guard */ 19 | export const isUint8Array = (input: unknown): input is Uint8Array => 20 | createTypeGuard( 21 | (value) => 22 | isTypedArray(value) && value[Symbol.toStringTag] === 'Uint8Array', 23 | )(input); 24 | 25 | /** @category Type Guard */ 26 | export const isUint8ClampedArray = ( 27 | input: unknown, 28 | ): input is Uint8ClampedArray => 29 | createTypeGuard( 30 | (value) => 31 | isTypedArray(value) && 32 | value[Symbol.toStringTag] === 'Uint8ClampedArray', 33 | )(input); 34 | 35 | /** @category Type Guard */ 36 | export const isInt16Array = (input: unknown): input is Int16Array => 37 | createTypeGuard( 38 | (value) => 39 | isTypedArray(value) && value[Symbol.toStringTag] === 'Int16Array', 40 | )(input); 41 | 42 | /** @category Type Guard */ 43 | export const isUint16Array = (input: unknown): input is Uint16Array => 44 | createTypeGuard( 45 | (value) => 46 | isTypedArray(value) && value[Symbol.toStringTag] === 'Uint16Array', 47 | )(input); 48 | 49 | /** @category Type Guard */ 50 | export const isInt32Array = (input: unknown): input is Int32Array => 51 | createTypeGuard( 52 | (value) => 53 | isTypedArray(value) && value[Symbol.toStringTag] === 'Int32Array', 54 | )(input); 55 | 56 | /** @category Type Guard */ 57 | export const isUint32Array = (input: unknown): input is Uint32Array => 58 | createTypeGuard( 59 | (value) => 60 | isTypedArray(value) && value[Symbol.toStringTag] === 'Uint32Array', 61 | )(input); 62 | 63 | /** @category Type Guard */ 64 | export const isFloat32Array = (input: unknown): input is Float32Array => 65 | createTypeGuard( 66 | (value) => 67 | isTypedArray(value) && value[Symbol.toStringTag] === 'Float32Array', 68 | )(input); 69 | 70 | /** @category Type Guard */ 71 | export const isFloat64Array = (input: unknown): input is Float64Array => 72 | createTypeGuard( 73 | (value) => 74 | isTypedArray(value) && value[Symbol.toStringTag] === 'Float64Array', 75 | )(input); 76 | 77 | /** @category Type Guard */ 78 | export const isBigInt64Array = (input: unknown): input is BigInt64Array => 79 | createTypeGuard( 80 | (value) => 81 | isTypedArray(value) && 82 | value[Symbol.toStringTag] === 'BigInt64Array', 83 | )(input); 84 | 85 | /** @category Type Guard */ 86 | export const isBigUint64Array = (input: unknown): input is BigUint64Array => 87 | createTypeGuard( 88 | (value) => 89 | isTypedArray(value) && 90 | value[Symbol.toStringTag] === 'BigUint64Array', 91 | )(input); 92 | -------------------------------------------------------------------------------- /src/guards/isUndefined.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard } from '../utils'; 2 | 3 | /** @category Type Guard */ 4 | export const isUndefined = createTypeGuard( 5 | (value) => value === undefined, 6 | ); 7 | -------------------------------------------------------------------------------- /src/guards/isWeakMap.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export function isWeakMap( 6 | input: unknown, 7 | ): input is WeakMap { 8 | return createTypeGuard>( 9 | (value) => 10 | value instanceof WeakMap || 11 | (isObject(value) && toObjectString(value) === '[object WeakMap]'), 12 | )(input); 13 | } 14 | -------------------------------------------------------------------------------- /src/guards/isWeakSet.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, toObjectString } from '../utils'; 2 | import { isObject } from './isObject'; 3 | 4 | /** @category Type Guard */ 5 | export function isWeakSet( 6 | input: unknown, 7 | ): input is WeakSet { 8 | return createTypeGuard>( 9 | (value) => 10 | value instanceof WeakSet || 11 | (isObject(value) && toObjectString(value) === '[object WeakSet]'), 12 | )(input); 13 | } 14 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './assertions/assertIsAnyArrayBuffer'; 2 | export * from './assertions/assertIsArgumentsObject'; 3 | export * from './assertions/assertIsArray'; 4 | export * from './assertions/assertIsArrayBuffer'; 5 | export * from './assertions/assertIsArrayBufferView'; 6 | export * from './assertions/assertIsAsyncFunction'; 7 | export * from './assertions/assertIsAsyncGenerator'; 8 | export * from './assertions/assertIsAsyncGeneratorFunction'; 9 | export * from './assertions/assertIsAsyncIterable'; 10 | export * from './assertions/assertIsBigInt'; 11 | export * from './assertions/assertIsBigIntObject'; 12 | export * from './assertions/assertIsBoolean'; 13 | export * from './assertions/assertIsBooleanObject'; 14 | export * from './assertions/assertIsBoxedPrimitive'; 15 | export * from './assertions/assertIsBuffer'; 16 | export * from './assertions/assertIsDataView'; 17 | export * from './assertions/assertIsDate'; 18 | export * from './assertions/assertIsDefined'; 19 | export * from './assertions/assertIsEmptyArray'; 20 | export * from './assertions/assertIsEmptyObject'; 21 | export * from './assertions/assertIsEmptyString'; 22 | export * from './assertions/assertIsError'; 23 | export * from './assertions/assertIsFinite'; 24 | export * from './assertions/assertIsFunction'; 25 | export * from './assertions/assertIsGenerator'; 26 | export * from './assertions/assertIsGeneratorFunction'; 27 | export * from './assertions/assertIsInteger'; 28 | export * from './assertions/assertIsIterable'; 29 | export * from './assertions/assertIsIterator'; 30 | export * from './assertions/assertIsMap'; 31 | export * from './assertions/assertIsMapIterator'; 32 | export * from './assertions/assertIsNaN'; 33 | export * from './assertions/assertIsNativeError'; 34 | export * from './assertions/assertIsNonEmptyArray'; 35 | export * from './assertions/assertIsNonEmptyString'; 36 | export * from './assertions/assertIsNotNull'; 37 | export * from './assertions/assertIsNotNullish'; 38 | export * from './assertions/assertIsNull'; 39 | export * from './assertions/assertIsNullish'; 40 | export * from './assertions/assertIsNumber'; 41 | export * from './assertions/assertIsNumberObject'; 42 | export * from './assertions/assertIsObject'; 43 | export * from './assertions/assertIsPlainObject'; 44 | export * from './assertions/assertIsPromise'; 45 | export * from './assertions/assertIsRecord'; 46 | export * from './assertions/assertIsRegExp'; 47 | export * from './assertions/assertIsSafeInteger'; 48 | export * from './assertions/assertIsSet'; 49 | export * from './assertions/assertIsSetIterator'; 50 | export * from './assertions/assertIsSharedArrayBuffer'; 51 | export * from './assertions/assertIsString'; 52 | export * from './assertions/assertIsStringObject'; 53 | export * from './assertions/assertIsSymbol'; 54 | export * from './assertions/assertIsSymbolObject'; 55 | export * from './assertions/assertIsTypedArray'; 56 | export * from './assertions/assertIsUndefined'; 57 | export * from './assertions/assertIsWeakMap'; 58 | export * from './assertions/assertIsWeakSet'; 59 | export * from './guards/isAnyArrayBuffer'; 60 | export * from './guards/isArgumentsObject'; 61 | export * from './guards/isArray'; 62 | export * from './guards/isArrayBuffer'; 63 | export * from './guards/isArrayBufferView'; 64 | export * from './guards/isAsyncFunction'; 65 | export * from './guards/isAsyncGenerator'; 66 | export * from './guards/isAsyncGeneratorFunction'; 67 | export * from './guards/isAsyncIterable'; 68 | export * from './guards/isBigInt'; 69 | export * from './guards/isBigIntObject'; 70 | export * from './guards/isBoolean'; 71 | export * from './guards/isBooleanObject'; 72 | export * from './guards/isBoxedPrimitive'; 73 | export * from './guards/isBuffer'; 74 | export * from './guards/isDataView'; 75 | export * from './guards/isDate'; 76 | export * from './guards/isDefined'; 77 | export * from './guards/isEmptyArray'; 78 | export * from './guards/isEmptyObject'; 79 | export * from './guards/isEmptyString'; 80 | export * from './guards/isError'; 81 | export * from './guards/isFinite'; 82 | export * from './guards/isFunction'; 83 | export * from './guards/isGenerator'; 84 | export * from './guards/isGeneratorFunction'; 85 | export * from './guards/isInteger'; 86 | export * from './guards/isIterable'; 87 | export * from './guards/isIterator'; 88 | export * from './guards/isMap'; 89 | export * from './guards/isMapIterator'; 90 | export * from './guards/isNaN'; 91 | export * from './guards/isNativeError'; 92 | export * from './guards/isNonEmptyArray'; 93 | export * from './guards/isNonEmptyString'; 94 | export * from './guards/isNotNull'; 95 | export * from './guards/isNotNullish'; 96 | export * from './guards/isNull'; 97 | export * from './guards/isNullish'; 98 | export * from './guards/isNumber'; 99 | export * from './guards/isNumberObject'; 100 | export * from './guards/isObject'; 101 | export * from './guards/isPlainObject'; 102 | export * from './guards/isPromise'; 103 | export * from './guards/isRecord'; 104 | export * from './guards/isRegExp'; 105 | export * from './guards/isSafeInteger'; 106 | export * from './guards/isSet'; 107 | export * from './guards/isSetIterator'; 108 | export * from './guards/isSharedArrayBuffer'; 109 | export * from './guards/isString'; 110 | export * from './guards/isStringObject'; 111 | export * from './guards/isSymbol'; 112 | export * from './guards/isSymbolObject'; 113 | export * from './guards/isTypedArray'; 114 | export * from './guards/isUndefined'; 115 | export * from './guards/isWeakMap'; 116 | export * from './guards/isWeakSet'; 117 | export * from './types'; 118 | export { createTypeGuard } from './utils'; 119 | export { isUnion } from './utils'; 120 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface ErrorMessage { 2 | message: string | undefined; 3 | } 4 | export interface KeyValidator { 5 | keyValidator: TypeValidator; 6 | } 7 | export type TypeAssertion< 8 | T, 9 | O extends TypeAssertionOptions | undefined = undefined, 10 | > = (input: unknown, options?: O) => asserts input is T; 11 | export type TypeAssertionOptions = Partial & TypeGuardOptions; 12 | export type TypedArray = 13 | | BigInt64Array 14 | | BigUint64Array 15 | | Float32Array 16 | | Float64Array 17 | | Int16Array 18 | | Int32Array 19 | | Int8Array 20 | | Uint16Array 21 | | Uint32Array 22 | | Uint8Array 23 | | Uint8ClampedArray; 24 | export type TypedGeneratorFunction = ( 25 | ...args: unknown[] 26 | ) => Generator; 27 | export type TypeGuard = ( 28 | input: unknown, 29 | options?: O, 30 | ) => input is T; 31 | export type TypeGuardOptions = Partial; 32 | export type TypeValidator = (input: unknown, ...args: unknown[]) => boolean; 33 | export interface ValueValidator { 34 | valueValidator: TypeValidator; 35 | } 36 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { TypeGuard, TypeGuardOptions, TypeValidator } from './types'; 2 | 3 | export const toObjectString = (value: unknown): string => 4 | Object.prototype.toString.call(value); 5 | 6 | /** 7 | * @category Utility 8 | * @example 9 | * 10 | * ```typescript 11 | * // myTypeGuard === (input: unknown, { throwError: boolean }) => input is MyClass 12 | * const myTypeGuard = createTypeGuard( 13 | * (value) => isObject(value) && Reflect.get(value, 'myProp'), 14 | * MyClass.name, 15 | * ); 16 | * ``` 17 | */ 18 | export function createTypeGuard< 19 | T, 20 | O extends TypeGuardOptions | undefined = undefined, 21 | >(validator: TypeValidator, options?: O): TypeGuard { 22 | return options 23 | ? (input: unknown): input is T => validator(input, options) 24 | : (input: unknown): input is T => validator(input); 25 | } 26 | 27 | /** 28 | * @category Utility 29 | * @example 30 | * 31 | * ```typescript 32 | * // unionTypeGuard === (input: unknown, ...args: unknown[]) => input is T 33 | * const unionTypeGuard = isUnion( 34 | * isString, 35 | * isNumber, 36 | * isSymbol, 37 | * ); 38 | * ``` 39 | */ 40 | export function isUnion(...guards: TypeGuard[]): TypeGuard { 41 | return function (input: unknown): input is T { 42 | for (const guard of guards) { 43 | if (guard(input)) { 44 | return true; 45 | } 46 | } 47 | return false; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /tests/assertions.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | assertIsAnyArrayBuffer, 3 | assertIsArgumentsObject, 4 | assertIsArray, 5 | assertIsArrayBuffer, 6 | assertIsArrayBufferView, 7 | assertIsAsyncFunction, 8 | assertIsAsyncGenerator, 9 | assertIsAsyncGeneratorFunction, 10 | assertIsAsyncIterable, 11 | assertIsBigInt, 12 | assertIsBigInt64Array, 13 | assertIsBigIntObject, 14 | assertIsBigUint64Array, 15 | assertIsBoolean, 16 | assertIsBooleanObject, 17 | assertIsBoxedPrimitive, 18 | assertIsBuffer, 19 | assertIsDataView, 20 | assertIsDate, 21 | assertIsDefined, 22 | assertIsEmptyArray, 23 | assertIsEmptyObject, 24 | assertIsEmptyString, 25 | assertIsError, 26 | assertIsFinite, 27 | assertIsFloat32Array, 28 | assertIsFloat64Array, 29 | assertIsFunction, 30 | assertIsGenerator, 31 | assertIsGeneratorFunction, 32 | assertIsInt8Array, 33 | assertIsInt16Array, 34 | assertIsInt32Array, 35 | assertIsInteger, 36 | assertIsIterable, 37 | assertIsIterator, 38 | assertIsMap, 39 | assertIsMapIterator, 40 | assertIsNaN, 41 | assertIsNativeError, 42 | assertIsNonEmptyArray, 43 | assertIsNonEmptyString, 44 | assertIsNotNull, 45 | assertIsNotNullish, 46 | assertIsNull, 47 | assertIsNullish, 48 | assertIsNumber, 49 | assertIsNumberObject, 50 | assertIsObject, 51 | assertIsPlainObject, 52 | assertIsPromise, 53 | assertIsRecord, 54 | assertIsRegExp, 55 | assertIsSafeInteger, 56 | assertIsSet, 57 | assertIsSetIterator, 58 | assertIsSharedArrayBuffer, 59 | assertIsString, 60 | assertIsStringObject, 61 | assertIsSymbol, 62 | assertIsSymbolObject, 63 | assertIsTypedArray, 64 | assertIsUint8Array, 65 | assertIsUint8ClampedArray, 66 | assertIsUint16Array, 67 | assertIsUint32Array, 68 | assertIsUndefined, 69 | assertIsWeakMap, 70 | assertIsWeakSet, 71 | ErrorMessage, 72 | isBoolean, 73 | isNumber, 74 | isObject, 75 | isString, 76 | isSymbol, 77 | isUnion, 78 | TypeAssertion, 79 | } from '../src'; 80 | 81 | const CUSTOM_MESSAGE = 'CUSTOM'; 82 | const asyncFunction = async () => null; 83 | const regularFunction = () => null; 84 | const generatorFunction = function* () { 85 | yield true; 86 | }; 87 | const asyncGeneratorFunction = async function* () { 88 | yield await asyncFunction(); 89 | }; 90 | const generator = generatorFunction(); 91 | const asyncGenerator = asyncGeneratorFunction(); 92 | const stringArray = ['xyz', 'abc', '123']; 93 | const numberArray = [1, 2, 3]; 94 | const symbolArray = [Symbol(), Symbol(), Symbol()]; 95 | const recordArray = [{ name: 1 }, { name: 2 }, { name: 3 }]; 96 | const stringMap = new Map([['xzy', 'abc']]); 97 | const numberMap = new Map([[100, 100]]); 98 | const symbolMap = new Map([[Symbol('x'), Symbol('y')]]); 99 | const booleanMap = new Map([[false, true]]); 100 | const recordMap = new Map([[{ key: 1 }, { value: 1 }]]); 101 | 102 | // eslint-disable-next-line @typescript-eslint/no-extraneous-class 103 | class CustomClass {} 104 | const stringRecord = { name: 'xyz' }; 105 | const numberRecord = { 1: 100 }; 106 | const symbolRecord = { [Symbol('a')]: Symbol('b') }; 107 | const promise = new Promise((resolve) => { 108 | resolve(null); 109 | }); 110 | const primitiveValues = [true, false, 0, 1, '', undefined, Symbol()]; 111 | const iterableObjects = [new Map(), new Set(), new String(''), []]; 112 | const buffers = [new ArrayBuffer(8), Buffer.alloc(8), new SharedArrayBuffer(8)]; 113 | const errors = [ 114 | new Error(), 115 | new TypeError(), 116 | new RangeError(), 117 | new SyntaxError(), 118 | new URIError(), 119 | new ReferenceError(), 120 | new EvalError(), 121 | ]; 122 | const typedArrays = [ 123 | new Int8Array(), 124 | new Uint8Array(), 125 | new Uint8ClampedArray(), 126 | new Int16Array(), 127 | new Uint16Array(), 128 | new Int32Array(), 129 | new Uint32Array(), 130 | new Float32Array(), 131 | new Float64Array(), 132 | new BigInt64Array(), 133 | new BigUint64Array(), 134 | ]; 135 | const objectValues = [ 136 | {}, 137 | 138 | new Number(0), 139 | 140 | new Boolean(false), 141 | new WeakMap(), 142 | new WeakSet(), 143 | ...iterableObjects, 144 | ...errors, 145 | ...buffers, 146 | ...typedArrays, 147 | ]; 148 | const functionValues = [ 149 | regularFunction, 150 | asyncFunction, 151 | asyncGeneratorFunction, 152 | generatorFunction, 153 | ]; 154 | 155 | describe('assertIsArray', () => { 156 | it('does not throw for positively tested array values', () => { 157 | expect(() => { 158 | assertIsArray(stringArray, { 159 | valueValidator: isString as any, 160 | }); 161 | }).not.toThrow(); 162 | expect(() => { 163 | assertIsArray(numberArray, { 164 | valueValidator: isNumber as any, 165 | }); 166 | }).not.toThrow(); 167 | expect(() => { 168 | assertIsArray(symbolArray, { 169 | valueValidator: isSymbol as any, 170 | }); 171 | }).not.toThrow(); 172 | expect(() => { 173 | assertIsArray(recordArray, { 174 | valueValidator: isObject as any, 175 | }); 176 | }).not.toThrow(); 177 | expect(() => { 178 | assertIsArray([...stringArray, ...numberArray], { 179 | valueValidator: isUnion( 180 | isString, 181 | isNumber, 182 | ) as any, 183 | }); 184 | }).not.toThrow(); 185 | }); 186 | it('throw for negatively tested array values', () => { 187 | expect(() => { 188 | assertIsArray(stringArray, { 189 | valueValidator: isNumber as any, 190 | }); 191 | }).toThrow(); 192 | expect(() => { 193 | assertIsArray(numberArray, { 194 | valueValidator: isString as any, 195 | }); 196 | }).toThrow(); 197 | expect(() => { 198 | assertIsArray(symbolArray, { 199 | valueValidator: isObject as any, 200 | }); 201 | }).toThrow(); 202 | expect(() => { 203 | assertIsArray(recordArray, { 204 | valueValidator: isSymbol as any, 205 | }); 206 | }).toThrow(); 207 | expect(() => { 208 | assertIsArray([...symbolArray, ...recordArray], { 209 | valueValidator: isUnion( 210 | isString, 211 | isNumber, 212 | ) as any, 213 | }); 214 | }).toThrow(); 215 | }); 216 | it('throws for non-array values', () => { 217 | expect(() => { 218 | assertIsArray('', { valueValidator: isString as any }); 219 | }).toThrow(); 220 | expect(() => { 221 | assertIsArray(null, { valueValidator: isString as any }); 222 | }).toThrow(); 223 | expect(() => { 224 | assertIsArray(123, { valueValidator: isString as any }); 225 | }).toThrow(); 226 | expect(() => { 227 | assertIsArray(Symbol(), { 228 | valueValidator: isString as any, 229 | }); 230 | }).toThrow(); 231 | expect(() => { 232 | assertIsArray({}, { valueValidator: isString as any }); 233 | }).toThrow(); 234 | }); 235 | it('throws custom message', () => { 236 | expect(() => { 237 | assertIsArray({}, { message: CUSTOM_MESSAGE }); 238 | }).toThrow(CUSTOM_MESSAGE); 239 | }); 240 | }); 241 | 242 | describe('assertIsSet', () => { 243 | it('does not throw for positively tested Set values', () => { 244 | expect(() => { 245 | assertIsSet(new Set(stringArray), { 246 | valueValidator: isString as any, 247 | }); 248 | }).not.toThrow(); 249 | expect(() => { 250 | assertIsSet(new Set(numberArray), { 251 | valueValidator: isNumber as any, 252 | }); 253 | }).not.toThrow(); 254 | expect(() => { 255 | assertIsSet(new Set(symbolArray), { 256 | valueValidator: isSymbol as any, 257 | }); 258 | }).not.toThrow(); 259 | expect(() => { 260 | assertIsSet(new Set(recordArray), { 261 | valueValidator: isObject as any, 262 | }); 263 | }).not.toThrow(); 264 | expect(() => { 265 | assertIsSet( 266 | new Set([...numberArray, ...stringArray]), 267 | { 268 | valueValidator: isUnion( 269 | isString, 270 | isNumber, 271 | ) as any, 272 | }, 273 | ); 274 | }).not.toThrow(); 275 | }); 276 | it('throws for negatively tested Set values', () => { 277 | expect(() => { 278 | assertIsSet(new Set(stringArray), { 279 | valueValidator: isNumber as any, 280 | }); 281 | }).toThrow(); 282 | expect(() => { 283 | assertIsSet(new Set(numberArray), { 284 | valueValidator: isString as any, 285 | }); 286 | }).toThrow(); 287 | expect(() => { 288 | assertIsSet(new Set(symbolArray), { 289 | valueValidator: isObject as any, 290 | }); 291 | }).toThrow(); 292 | expect(() => { 293 | assertIsSet(new Set(recordArray), { 294 | valueValidator: isSymbol as any, 295 | }); 296 | }).toThrow(); 297 | expect(() => { 298 | assertIsSet( 299 | new Set([...recordArray, ...symbolArray]), 300 | { 301 | valueValidator: isUnion( 302 | isString, 303 | isNumber, 304 | ) as any, 305 | }, 306 | ); 307 | }).toThrow(); 308 | }); 309 | it('throws for non-Set values', () => { 310 | expect(() => { 311 | assertIsSet('', { valueValidator: isString as any }); 312 | }).toThrow(); 313 | expect(() => { 314 | assertIsSet(null, { valueValidator: isString as any }); 315 | }).toThrow(); 316 | expect(() => { 317 | assertIsSet(123, { valueValidator: isString as any }); 318 | }).toThrow(); 319 | expect(() => { 320 | assertIsSet(Symbol(), { valueValidator: isString as any }); 321 | }).toThrow(); 322 | expect(() => { 323 | assertIsSet({}, { valueValidator: isString as any }); 324 | }).toThrow(); 325 | }); 326 | it('throws custom message', () => { 327 | expect(() => { 328 | assertIsSet({}, { message: CUSTOM_MESSAGE }); 329 | }).toThrow(CUSTOM_MESSAGE); 330 | }); 331 | }); 332 | 333 | describe('assertIsMap', () => { 334 | it('does not throw for positively tested Map values', () => { 335 | expect(() => { 336 | assertIsMap(stringMap, { 337 | keyValidator: isString as any, 338 | valueValidator: isString as any, 339 | }); 340 | }).not.toThrow(); 341 | expect(() => { 342 | assertIsMap(numberMap, { 343 | keyValidator: isNumber as any, 344 | valueValidator: isNumber as any, 345 | }); 346 | }).not.toThrow(); 347 | expect(() => { 348 | assertIsMap(symbolMap, { 349 | keyValidator: isSymbol as any, 350 | valueValidator: isSymbol as any, 351 | }); 352 | }).not.toThrow(); 353 | expect(() => { 354 | assertIsMap( 355 | new Map([ 356 | ...stringMap, 357 | ...numberMap, 358 | ...symbolMap, 359 | ]), 360 | { 361 | keyValidator: isUnion( 362 | isString, 363 | isNumber, 364 | isSymbol, 365 | ) as any, 366 | valueValidator: isUnion( 367 | isString, 368 | isNumber, 369 | isSymbol, 370 | ) as any, 371 | }, 372 | ); 373 | }).not.toThrow(); 374 | expect(() => { 375 | assertIsMap( 376 | new Map([ 377 | ...recordMap, 378 | ...booleanMap, 379 | ]), 380 | { 381 | keyValidator: isUnion( 382 | isObject, 383 | isBoolean, 384 | ) as any, 385 | valueValidator: isUnion( 386 | isObject, 387 | isBoolean, 388 | ) as any, 389 | }, 390 | ); 391 | }).not.toThrow(); 392 | }); 393 | it('throws for negatively tested Map values', () => { 394 | expect(() => { 395 | assertIsMap(stringMap, { 396 | keyValidator: (key: unknown): key is number => isNumber(key), 397 | valueValidator: (value: unknown): value is number => 398 | isNumber(value), 399 | }); 400 | }).toThrow(); 401 | expect(() => { 402 | assertIsMap(numberMap, { 403 | keyValidator: (key: unknown): key is string => isString(key), 404 | valueValidator: (value: unknown): value is string => 405 | isString(value), 406 | }); 407 | }).toThrow(); 408 | }); 409 | it('throws for non-Map values', () => { 410 | expect(() => { 411 | assertIsMap(''); 412 | }).toThrow(); 413 | expect(() => { 414 | assertIsMap(true); 415 | }).toThrow(); 416 | expect(() => { 417 | assertIsMap(new Set()); 418 | }).toThrow(); 419 | expect(() => { 420 | assertIsMap([]); 421 | }).toThrow(); 422 | expect(() => { 423 | assertIsMap(new WeakMap()); 424 | }).toThrow(); 425 | }); 426 | it('throws custom message', () => { 427 | expect(() => { 428 | assertIsMap({}, { message: CUSTOM_MESSAGE }); 429 | }).toThrow(CUSTOM_MESSAGE); 430 | }); 431 | }); 432 | 433 | describe('assertIsRecord', () => { 434 | it('returns true for positively tested record values', () => { 435 | expect(() => { 436 | assertIsRecord(stringRecord, { 437 | keyValidator: isString as any, 438 | valueValidator: isString as any, 439 | }); 440 | }).not.toThrow(); 441 | expect(() => { 442 | assertIsRecord(numberRecord, { 443 | keyValidator: isString as any, 444 | valueValidator: isNumber as any, 445 | }); 446 | }).not.toThrow(); 447 | expect(() => { 448 | assertIsRecord(symbolRecord, { 449 | keyValidator: isSymbol as any, 450 | valueValidator: isSymbol as any, 451 | }); 452 | }).not.toThrow(); 453 | expect(() => { 454 | assertIsRecord( 455 | { 456 | ...stringRecord, 457 | ...numberRecord, 458 | ...symbolRecord, 459 | }, 460 | { 461 | keyValidator: isUnion( 462 | isString, 463 | isNumber, 464 | isSymbol, 465 | ) as any, 466 | valueValidator: isUnion( 467 | isString, 468 | isNumber, 469 | isSymbol, 470 | ) as any, 471 | }, 472 | ); 473 | }).not.toThrow(); 474 | }); 475 | it('returns false for negatively tested record values', () => { 476 | expect(() => { 477 | assertIsRecord(stringRecord, { 478 | keyValidator: (v: unknown): v is string => isString(v), 479 | valueValidator: (v: unknown): v is number => isNumber(v), 480 | }); 481 | }).toThrow(); 482 | expect(() => { 483 | assertIsRecord(numberRecord, { 484 | keyValidator: (v: unknown): v is string => isString(v), 485 | valueValidator: (v: unknown): v is string => isString(v), 486 | }); 487 | }).toThrow(); 488 | }); 489 | it('returns false for non-record values', () => { 490 | expect(() => { 491 | assertIsRecord(CustomClass); 492 | }).toThrow(); 493 | expect(() => { 494 | assertIsRecord(new Map()); 495 | }).toThrow(); 496 | expect(() => { 497 | assertIsRecord(new Set()); 498 | }).toThrow(); 499 | expect(() => { 500 | assertIsRecord([]); 501 | }).toThrow(); 502 | expect(() => { 503 | assertIsRecord(new WeakMap()); 504 | }).toThrow(); 505 | }); 506 | it('throws custom message', () => { 507 | expect(() => { 508 | assertIsRecord([], { message: CUSTOM_MESSAGE }); 509 | }).toThrow(CUSTOM_MESSAGE); 510 | }); 511 | }); 512 | 513 | describe.each([ 514 | [ 515 | 'string', 516 | assertIsString, 517 | ['abc'], 518 | [1, true, null, ...objectValues, ...functionValues], 519 | ], 520 | [ 521 | 'number', 522 | assertIsNumber, 523 | [0, 1], 524 | ['abc', true, null, ...objectValues, ...functionValues], 525 | ], 526 | [ 527 | 'bigint', 528 | assertIsBigInt, 529 | [9_007_199_254_740_991n, BigInt(9_007_199_254_740_991)], 530 | [0, 1, 'abc', true, null, ...objectValues, ...functionValues], 531 | ], 532 | [ 533 | 'boolean', 534 | assertIsBoolean, 535 | [true, false], 536 | ['', 0, null, ...objectValues, ...functionValues], 537 | ], 538 | [ 539 | 'symbol', 540 | assertIsSymbol, 541 | [Symbol()], 542 | ['', 0, null, true, ...objectValues, ...functionValues], 543 | ], 544 | [ 545 | 'undefined', 546 | assertIsUndefined, 547 | [undefined], 548 | ['', 0, null, false, ...objectValues, ...functionValues], 549 | ], 550 | [ 551 | 'object', 552 | assertIsObject, 553 | objectValues, 554 | [null, ...primitiveValues, ...functionValues], 555 | ], 556 | [ 557 | 'null', 558 | assertIsNull, 559 | [null], 560 | ['', 0, undefined, false, ...objectValues, ...functionValues], 561 | ], 562 | [ 563 | 'nullish', 564 | assertIsNullish, 565 | [null, undefined], 566 | ['', 0, false, ...objectValues, ...functionValues], 567 | ], 568 | [ 569 | 'Defined', 570 | assertIsDefined, 571 | ['', 0, null, false, ...objectValues, ...functionValues], 572 | [undefined], 573 | ], 574 | [ 575 | 'notNull', 576 | assertIsNotNull, 577 | ['', 0, undefined, false, ...objectValues, ...functionValues], 578 | [null], 579 | ], 580 | [ 581 | 'notNullish', 582 | assertIsNotNullish, 583 | ['', 0, false, ...objectValues, ...functionValues], 584 | [null, undefined], 585 | ], 586 | [ 587 | 'Error', 588 | assertIsError, 589 | errors, 590 | [ 591 | ...primitiveValues, 592 | ...objectValues.filter((v) => !(v instanceof Error)), 593 | ...functionValues, 594 | ], 595 | ], 596 | [ 597 | 'Buffer', 598 | assertIsBuffer, 599 | [Buffer.alloc(8), Buffer.alloc(16)], 600 | [ 601 | ...primitiveValues, 602 | ...objectValues.filter((v) => !(v instanceof Buffer)), 603 | ...functionValues, 604 | ], 605 | ], 606 | [ 607 | 'ArrayBuffer', 608 | assertIsArrayBuffer, 609 | [new ArrayBuffer(8), new ArrayBuffer(16)], 610 | [ 611 | ...primitiveValues, 612 | ...objectValues.filter((v) => !(v instanceof ArrayBuffer)), 613 | ...functionValues, 614 | ], 615 | ], 616 | [ 617 | 'SharedArrayBuffer', 618 | assertIsSharedArrayBuffer, 619 | [new SharedArrayBuffer(8), new SharedArrayBuffer(16)], 620 | [ 621 | ...primitiveValues, 622 | ...objectValues.filter((v) => !(v instanceof SharedArrayBuffer)), 623 | ...functionValues, 624 | ], 625 | ], 626 | [ 627 | 'AnyArrayBuffer', 628 | assertIsAnyArrayBuffer, 629 | [new SharedArrayBuffer(8), new ArrayBuffer(16)], 630 | [ 631 | ...primitiveValues, 632 | ...objectValues.filter( 633 | (v) => 634 | !(v instanceof SharedArrayBuffer) && 635 | !(v instanceof ArrayBuffer), 636 | ), 637 | ...functionValues, 638 | ], 639 | ], 640 | [ 641 | 'RegExp', 642 | assertIsRegExp, 643 | [new RegExp('test'), /'test'/], 644 | [...primitiveValues, ...objectValues, ...functionValues], 645 | ], 646 | [ 647 | 'Date', 648 | assertIsDate, 649 | [new Date()], 650 | [...primitiveValues, ...objectValues, ...functionValues], 651 | ], 652 | [ 653 | 'String', 654 | assertIsStringObject, 655 | [new String('x')], 656 | [ 657 | ...primitiveValues, 658 | ...objectValues.filter( 659 | (v) => Object.prototype.toString.call(v) !== '[object String]', 660 | ), 661 | ...functionValues, 662 | ], 663 | ], 664 | [ 665 | 'Boolean', 666 | assertIsBooleanObject, 667 | [new Boolean(true)], 668 | [ 669 | ...primitiveValues, 670 | ...objectValues.filter( 671 | (v) => Object.prototype.toString.call(v) !== '[object Boolean]', 672 | ), 673 | ...functionValues, 674 | ], 675 | ], 676 | [ 677 | 'Number', 678 | assertIsNumberObject, 679 | [new Number(1)], 680 | [ 681 | ...primitiveValues, 682 | ...objectValues.filter( 683 | (v) => Object.prototype.toString.call(v) !== '[object Number]', 684 | ), 685 | ...functionValues, 686 | ], 687 | ], 688 | [ 689 | 'Promise', 690 | assertIsPromise, 691 | [promise], 692 | [...objectValues, ...functionValues, ...primitiveValues], 693 | ], 694 | [ 695 | 'Function', 696 | assertIsFunction, 697 | [regularFunction], 698 | [ 699 | asyncFunction, 700 | generatorFunction, 701 | asyncGeneratorFunction, 702 | ...primitiveValues, 703 | ...objectValues, 704 | ], 705 | ], 706 | [ 707 | 'AsyncFunction', 708 | assertIsAsyncFunction, 709 | [asyncFunction], 710 | [ 711 | regularFunction, 712 | generatorFunction, 713 | asyncGeneratorFunction, 714 | ...primitiveValues, 715 | ...objectValues, 716 | ], 717 | ], 718 | [ 719 | 'GeneratorFunction', 720 | assertIsGeneratorFunction, 721 | [generatorFunction], 722 | [ 723 | regularFunction, 724 | asyncFunction, 725 | asyncGeneratorFunction, 726 | ...primitiveValues, 727 | ...objectValues, 728 | ], 729 | ], 730 | [ 731 | 'AsyncGeneratorFunction', 732 | assertIsAsyncGeneratorFunction, 733 | [asyncGeneratorFunction], 734 | [ 735 | regularFunction, 736 | asyncFunction, 737 | generatorFunction, 738 | ...objectValues, 739 | ...primitiveValues, 740 | ], 741 | ], 742 | [ 743 | 'Generator', 744 | assertIsGenerator, 745 | [generator], 746 | [ 747 | asyncGenerator, 748 | ...objectValues, 749 | ...functionValues, 750 | ...primitiveValues, 751 | ], 752 | ], 753 | [ 754 | 'AsyncGenerator', 755 | assertIsAsyncGenerator, 756 | [asyncGenerator], 757 | [generator, ...objectValues, ...functionValues, ...primitiveValues], 758 | ], 759 | [ 760 | 'Iterable', 761 | assertIsIterable, 762 | [...iterableObjects, generator, '', ...typedArrays], 763 | [ 764 | ...errors, 765 | {}, 766 | ...functionValues, 767 | ...primitiveValues.filter((v) => typeof v !== 'string'), 768 | ], 769 | ], 770 | [ 771 | 'AsyncIterable', 772 | assertIsAsyncIterable, 773 | [asyncGenerator], 774 | [...errors, ...typedArrays, {}, ...functionValues, ...primitiveValues], 775 | ], 776 | [ 777 | 'Iterator', 778 | assertIsIterator, 779 | [asyncGenerator, generator, new Map().values(), new Set().values()], 780 | [ 781 | ...errors, 782 | {}, 783 | ...objectValues, 784 | ...typedArrays, 785 | ...functionValues, 786 | ...primitiveValues, 787 | ], 788 | ], 789 | [ 790 | 'TypedArray', 791 | assertIsTypedArray, 792 | typedArrays, 793 | [ 794 | ...objectValues.filter( 795 | (v) => ![...buffers, ...typedArrays].includes(v as any), 796 | ), 797 | ...functionValues, 798 | ...primitiveValues, 799 | ], 800 | ], 801 | [ 802 | 'Int8Array', 803 | assertIsInt8Array, 804 | [new Int8Array()], 805 | [ 806 | ...objectValues.filter( 807 | (v) => ![...buffers, ...typedArrays].includes(v as any), 808 | ), 809 | 810 | ...functionValues, 811 | ...primitiveValues, 812 | ], 813 | ], 814 | [ 815 | 'Uint8Array', 816 | assertIsUint8Array, 817 | [new Uint8Array()], 818 | [ 819 | ...objectValues.filter( 820 | (v) => ![...buffers, ...typedArrays].includes(v as any), 821 | ), 822 | 823 | ...functionValues, 824 | ...primitiveValues, 825 | ], 826 | ], 827 | [ 828 | 'Uint8ClampedArray', 829 | assertIsUint8ClampedArray, 830 | [new Uint8ClampedArray()], 831 | [ 832 | ...objectValues.filter( 833 | (v) => ![...buffers, ...typedArrays].includes(v as any), 834 | ), 835 | 836 | ...functionValues, 837 | ...primitiveValues, 838 | ], 839 | ], 840 | [ 841 | 'Int16Array', 842 | assertIsInt16Array, 843 | [new Int16Array()], 844 | [ 845 | ...objectValues.filter( 846 | (v) => ![...buffers, ...typedArrays].includes(v as any), 847 | ), 848 | 849 | ...functionValues, 850 | ...primitiveValues, 851 | ], 852 | ], 853 | [ 854 | 'Uint16Array', 855 | assertIsUint16Array, 856 | [new Uint16Array()], 857 | [ 858 | ...objectValues.filter( 859 | (v) => ![...buffers, ...typedArrays].includes(v as any), 860 | ), 861 | 862 | ...functionValues, 863 | ...primitiveValues, 864 | ], 865 | ], 866 | [ 867 | 'Int32Array', 868 | assertIsInt32Array, 869 | [new Int32Array()], 870 | [ 871 | ...objectValues.filter( 872 | (v) => ![...buffers, ...typedArrays].includes(v as any), 873 | ), 874 | 875 | ...functionValues, 876 | ...primitiveValues, 877 | ], 878 | ], 879 | [ 880 | 'Uint32Array', 881 | assertIsUint32Array, 882 | [new Uint32Array()], 883 | [ 884 | ...objectValues.filter( 885 | (v) => ![...buffers, ...typedArrays].includes(v as any), 886 | ), 887 | 888 | ...functionValues, 889 | ...primitiveValues, 890 | ], 891 | ], 892 | [ 893 | 'Float32Array', 894 | assertIsFloat32Array, 895 | [new Float32Array()], 896 | [ 897 | ...objectValues.filter( 898 | (v) => ![...buffers, ...typedArrays].includes(v as any), 899 | ), 900 | 901 | ...functionValues, 902 | ...primitiveValues, 903 | ], 904 | ], 905 | [ 906 | 'Float64Array', 907 | assertIsFloat64Array, 908 | [new Float64Array()], 909 | [ 910 | ...objectValues.filter( 911 | (v) => ![...buffers, ...typedArrays].includes(v as any), 912 | ), 913 | 914 | ...functionValues, 915 | ...primitiveValues, 916 | ], 917 | ], 918 | [ 919 | 'BigInt64Array', 920 | assertIsBigInt64Array, 921 | [new BigInt64Array()], 922 | [ 923 | ...objectValues.filter( 924 | (v) => ![...buffers, ...typedArrays].includes(v as any), 925 | ), 926 | 927 | ...functionValues, 928 | ...primitiveValues, 929 | ], 930 | ], 931 | [ 932 | 'BigUint64Array', 933 | assertIsBigUint64Array, 934 | [new BigUint64Array()], 935 | [ 936 | ...objectValues.filter( 937 | (v) => ![...buffers, ...typedArrays].includes(v as any), 938 | ), 939 | 940 | ...functionValues, 941 | ...primitiveValues, 942 | ], 943 | ], 944 | [ 945 | 'DataView', 946 | assertIsDataView, 947 | [new DataView(new ArrayBuffer(8))], 948 | [...objectValues, ...primitiveValues, ...functionValues], 949 | ], 950 | [ 951 | 'WeakMap', 952 | assertIsWeakMap, 953 | [new WeakMap([[stringRecord, '123']])], 954 | [ 955 | ...objectValues.filter((v) => !(v instanceof WeakMap)), 956 | ...primitiveValues, 957 | ...functionValues, 958 | ], 959 | ], 960 | [ 961 | 'WeakSet', 962 | assertIsWeakSet, 963 | [new WeakSet([stringRecord, numberRecord])], 964 | [ 965 | ...objectValues.filter((v) => !(v instanceof WeakSet)), 966 | ...primitiveValues, 967 | ...functionValues, 968 | ], 969 | ], 970 | [ 971 | 'ArgumentsObject', 972 | assertIsArgumentsObject, 973 | [ 974 | (function () { 975 | // @ts-ignore 976 | return arguments; 977 | // @ts-ignore 978 | })(1, 2, 3), 979 | ], 980 | [{}, [], null, undefined, ...functionValues, ...primitiveValues], 981 | ], 982 | [ 983 | 'ArrayBufferView', 984 | assertIsArrayBufferView, 985 | [ 986 | new Uint8Array(), 987 | new Uint16Array(), 988 | new Uint32Array(), 989 | new Int8Array(), 990 | new Int16Array(), 991 | new Int32Array(), 992 | new Float32Array(), 993 | new Float64Array(), 994 | new DataView(new ArrayBuffer(8)), 995 | ], 996 | [ 997 | new ArrayBuffer(8), 998 | [], 999 | {}, 1000 | null, 1001 | undefined, 1002 | ...functionValues, 1003 | ...primitiveValues, 1004 | ], 1005 | ], 1006 | [ 1007 | 'BigIntObject', 1008 | assertIsBigIntObject, 1009 | [new Object(BigInt(123))], 1010 | [ 1011 | BigInt(123), 1012 | 123, 1013 | '123', 1014 | null, 1015 | undefined, 1016 | ...objectValues.filter( 1017 | (v) => 1018 | !(Object.prototype.toString.call(v) === '[object BigInt]'), 1019 | ), 1020 | ...functionValues, 1021 | ], 1022 | ], 1023 | [ 1024 | 'BoxedPrimitive', 1025 | assertIsBoxedPrimitive, 1026 | [ 1027 | new Object('string'), 1028 | new Object(123), 1029 | new Object(true), 1030 | new Object(Symbol('test')), 1031 | new Object(BigInt(123)), 1032 | ], 1033 | [ 1034 | 'string', 1035 | 123, 1036 | true, 1037 | Symbol('test'), 1038 | BigInt(123), 1039 | null, 1040 | undefined, 1041 | {}, 1042 | [], 1043 | ...functionValues, 1044 | ], 1045 | ], 1046 | [ 1047 | 'EmptyArray', 1048 | assertIsEmptyArray, 1049 | [[]], 1050 | [ 1051 | [1], 1052 | ['a'], 1053 | {}, 1054 | '', 1055 | null, 1056 | undefined, 1057 | ...objectValues.filter((v) => !Array.isArray(v)), 1058 | ...functionValues, 1059 | ], 1060 | ], 1061 | [ 1062 | 'EmptyObject', 1063 | assertIsEmptyObject, 1064 | [{}], 1065 | [ 1066 | { a: 1 }, 1067 | [], 1068 | '', 1069 | null, 1070 | undefined, 1071 | ...objectValues.filter((v) => Object.keys(v as object).length > 0), 1072 | ...functionValues, 1073 | ], 1074 | ], 1075 | [ 1076 | 'EmptyString', 1077 | assertIsEmptyString, 1078 | [''], 1079 | [ 1080 | 'a', 1081 | ' ', 1082 | [], 1083 | {}, 1084 | null, 1085 | undefined, 1086 | ...objectValues.filter((v) => typeof v !== 'string'), 1087 | ...functionValues, 1088 | ], 1089 | ], 1090 | [ 1091 | 'Finite', 1092 | assertIsFinite, 1093 | [0, 1, -1, 1.5, Number.MAX_VALUE, -Number.MAX_VALUE], 1094 | [ 1095 | Infinity, 1096 | -Infinity, 1097 | Number.NaN, 1098 | '1', 1099 | true, 1100 | null, 1101 | undefined, 1102 | ...objectValues, 1103 | ...functionValues, 1104 | ], 1105 | ], 1106 | [ 1107 | 'Integer', 1108 | assertIsInteger, 1109 | [0, 1, -1, Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER], 1110 | [1.5, '1', true, null, undefined, ...objectValues, ...functionValues], 1111 | ], 1112 | [ 1113 | 'MapIterator', 1114 | assertIsMapIterator, 1115 | [new Map().entries()], 1116 | [ 1117 | new Map(), 1118 | new Set(), 1119 | [], 1120 | {}, 1121 | null, 1122 | undefined, 1123 | ...functionValues, 1124 | ...primitiveValues, 1125 | ], 1126 | ], 1127 | [ 1128 | 'NaN', 1129 | assertIsNaN, 1130 | [Number.NaN, Number.NaN], 1131 | [0, 'NaN', null, undefined, ...objectValues, ...functionValues], 1132 | ], 1133 | [ 1134 | 'NativeError', 1135 | assertIsNativeError, 1136 | [new Error(), new TypeError(), new RangeError()], 1137 | [ 1138 | { message: 'error', name: 'Error' }, 1139 | null, 1140 | undefined, 1141 | ...objectValues.filter((v) => !(v instanceof Error)), 1142 | ...functionValues, 1143 | ], 1144 | ], 1145 | [ 1146 | 'NonEmptyArray', 1147 | assertIsNonEmptyArray, 1148 | [[1], ['a'], [{}], [null], [undefined]], 1149 | [ 1150 | [], 1151 | {}, 1152 | '', 1153 | null, 1154 | undefined, 1155 | ...objectValues.filter((v) => !Array.isArray(v)), 1156 | ...functionValues, 1157 | ], 1158 | ], 1159 | [ 1160 | 'NonEmptyString', 1161 | assertIsNonEmptyString, 1162 | ['a', ' ', 'test', '0', 'false'], 1163 | [ 1164 | '', 1165 | [], 1166 | {}, 1167 | null, 1168 | undefined, 1169 | ...objectValues.filter((v) => typeof v !== 'string'), 1170 | ...functionValues, 1171 | ], 1172 | ], 1173 | [ 1174 | 'PlainObject', 1175 | assertIsPlainObject, 1176 | [ 1177 | {}, 1178 | { a: 1 }, 1179 | Object.create(null), 1180 | Object.create(Object.prototype), 1181 | Object.create(Object.create(null)), 1182 | ], 1183 | [ 1184 | new Date(), 1185 | [], 1186 | null, 1187 | undefined, 1188 | new CustomClass(), 1189 | ...functionValues, 1190 | ...primitiveValues.filter( 1191 | (v): v is boolean | number | string | symbol => 1192 | Boolean(v) || v === false || v === 0 || v === '', 1193 | ), 1194 | ], 1195 | ], 1196 | [ 1197 | 'SafeInteger', 1198 | assertIsSafeInteger, 1199 | [0, 1, -1, Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER], 1200 | [ 1201 | Number.MAX_SAFE_INTEGER + 1, 1202 | -Number.MAX_SAFE_INTEGER - 1, 1203 | 1.5, 1204 | '1', 1205 | true, 1206 | null, 1207 | undefined, 1208 | ...objectValues, 1209 | ...functionValues, 1210 | ], 1211 | ], 1212 | [ 1213 | 'SetIterator', 1214 | assertIsSetIterator, 1215 | [new Set().values()], 1216 | [ 1217 | new Set(), 1218 | new Map(), 1219 | [], 1220 | {}, 1221 | null, 1222 | undefined, 1223 | ...functionValues, 1224 | ...primitiveValues, 1225 | ], 1226 | ], 1227 | [ 1228 | 'SymbolObject', 1229 | assertIsSymbolObject, 1230 | [new Object(Symbol('test'))], 1231 | [ 1232 | Symbol('test'), 1233 | 'symbol', 1234 | {}, 1235 | [], 1236 | null, 1237 | undefined, 1238 | ...objectValues.filter( 1239 | (v) => 1240 | !(Object.prototype.toString.call(v) === '[object Symbol]'), 1241 | ), 1242 | ...functionValues, 1243 | ], 1244 | ], 1245 | ])( 1246 | '%s', 1247 | // @ts-ignore - complex test type 1248 | ( 1249 | _: string, 1250 | assertion: TypeAssertion, 1251 | expected: unknown[], 1252 | failed: unknown[], 1253 | ) => { 1254 | it.each(expected.map((v) => [v]))( 1255 | `does not throw for expected values`, 1256 | (value) => { 1257 | expect(() => { 1258 | assertion(value); 1259 | }).not.toThrow(); 1260 | }, 1261 | ); 1262 | it.each(failed.map((v) => [v]))( 1263 | `throws for non-expected values`, 1264 | (value) => { 1265 | expect(() => { 1266 | assertion(value); 1267 | }).toThrow(); 1268 | }, 1269 | ); 1270 | it.each(failed.map((v) => [v]))(`with custom message`, (value) => { 1271 | expect(() => { 1272 | assertion(value, { message: CUSTOM_MESSAGE }); 1273 | }).toThrow(CUSTOM_MESSAGE); 1274 | }); 1275 | }, 1276 | ); 1277 | -------------------------------------------------------------------------------- /tests/guards.spec.ts: -------------------------------------------------------------------------------- 1 | import { expectTypeOf } from 'expect-type'; 2 | 3 | import { 4 | isAnyArrayBuffer, 5 | isArgumentsObject, 6 | isArray, 7 | isArrayBuffer, 8 | isArrayBufferView, 9 | isAsyncFunction, 10 | isAsyncGenerator, 11 | isAsyncGeneratorFunction, 12 | isAsyncIterable, 13 | isBigInt, 14 | isBigInt64Array, 15 | isBigIntObject, 16 | isBigUint64Array, 17 | isBoolean, 18 | isBooleanObject, 19 | isBoxedPrimitive, 20 | isBuffer, 21 | isDataView, 22 | isDate, 23 | isDefined, 24 | isEmptyArray, 25 | isEmptyObject, 26 | isEmptyString, 27 | isError, 28 | isFinite, 29 | isFloat32Array, 30 | isFloat64Array, 31 | isFunction, 32 | isGenerator, 33 | isGeneratorFunction, 34 | isInt8Array, 35 | isInt16Array, 36 | isInt32Array, 37 | isInteger, 38 | isIterable, 39 | isIterator, 40 | isMap, 41 | isMapIterator, 42 | isNaN, 43 | isNativeError, 44 | isNonEmptyArray, 45 | isNonEmptyString, 46 | isNotNull, 47 | isNotNullish, 48 | isNull, 49 | isNullish, 50 | isNumber, 51 | isNumberObject, 52 | isObject, 53 | isPlainObject, 54 | isPromise, 55 | isRecord, 56 | isRegExp, 57 | isSafeInteger, 58 | isSet, 59 | isSetIterator, 60 | isSharedArrayBuffer, 61 | isString, 62 | isStringObject, 63 | isSymbol, 64 | isSymbolObject, 65 | isTypedArray, 66 | isUint8Array, 67 | isUint8ClampedArray, 68 | isUint16Array, 69 | isUint32Array, 70 | isUndefined, 71 | isUnion, 72 | isWeakMap, 73 | isWeakSet, 74 | TypeGuard, 75 | } from '../src'; 76 | 77 | const asyncFunction = async () => null; 78 | const regularFunction = () => null; 79 | const generatorFunction = function* () { 80 | yield true; 81 | }; 82 | const asyncGeneratorFunction = async function* () { 83 | yield await asyncFunction(); 84 | }; 85 | const generator = generatorFunction(); 86 | const asyncGenerator = asyncGeneratorFunction(); 87 | const stringArray = ['xyz', 'abc', '123']; 88 | const numberArray = [1, 2, 3]; 89 | const symbolArray = [Symbol(), Symbol(), Symbol()]; 90 | const recordArray = [{ name: 1 }, { name: 2 }, { name: 3 }]; 91 | const stringMap = new Map([['xzy', 'abc']]); 92 | const numberMap = new Map([[100, 100]]); 93 | const symbolMap = new Map([[Symbol('x'), Symbol('y')]]); 94 | const booleanMap = new Map([[false, true]]); 95 | const recordMap = new Map([[{ key: 1 }, { value: 1 }]]); 96 | 97 | // eslint-disable-next-line @typescript-eslint/no-extraneous-class 98 | class CustomClass {} 99 | const stringRecord = { name: 'xyz' }; 100 | const numberRecord = { 1: 100 }; 101 | const symbolRecord = { [Symbol('a')]: Symbol('b') }; 102 | const promise = new Promise((resolve) => { 103 | resolve(null); 104 | }); 105 | const primitiveValues = [true, false, 0, 1, '', undefined, Symbol()]; 106 | const iterableObjects = [new Map(), new Set(), new String(''), []]; 107 | const buffers = [new ArrayBuffer(8), Buffer.alloc(8), new SharedArrayBuffer(8)]; 108 | const errors = [ 109 | new Error(), 110 | new TypeError(), 111 | new RangeError(), 112 | new SyntaxError(), 113 | new URIError(), 114 | new ReferenceError(), 115 | new EvalError(), 116 | ]; 117 | const typedArrays = [ 118 | new Int8Array(), 119 | new Uint8Array(), 120 | new Uint8ClampedArray(), 121 | new Int16Array(), 122 | new Uint16Array(), 123 | new Int32Array(), 124 | new Uint32Array(), 125 | new Float32Array(), 126 | new Float64Array(), 127 | new BigInt64Array(), 128 | new BigUint64Array(), 129 | ]; 130 | const objectValues = [ 131 | {}, 132 | new Number(0), 133 | new Boolean(false), 134 | new WeakMap(), 135 | new WeakSet(), 136 | ...iterableObjects, 137 | ...errors, 138 | ...buffers, 139 | ...typedArrays, 140 | ]; 141 | const functionValues = [ 142 | regularFunction, 143 | asyncFunction, 144 | asyncGeneratorFunction, 145 | generatorFunction, 146 | ]; 147 | 148 | describe('isArray', () => { 149 | it('returns true for positively tested array values', () => { 150 | expect( 151 | isArray(stringArray, { 152 | valueValidator: (v) => isString(v), 153 | }), 154 | ).toBeTruthy(); 155 | expect( 156 | isArray(numberArray, { 157 | valueValidator: (v) => isNumber(v), 158 | }), 159 | ).toBeTruthy(); 160 | expect( 161 | isArray(symbolArray, { 162 | valueValidator: (v) => isSymbol(v), 163 | }), 164 | ).toBeTruthy(); 165 | expect( 166 | isArray(recordArray, { 167 | valueValidator: (v) => isObject(v), 168 | }), 169 | ).toBeTruthy(); 170 | expect( 171 | isArray([...stringArray, ...numberArray], { 172 | valueValidator: (v) => 173 | isUnion(isString, isNumber)(v), 174 | }), 175 | ).toBeTruthy(); 176 | }); 177 | it('returns false for negatively tested array values', () => { 178 | expect( 179 | isArray(stringArray, { 180 | valueValidator: (v) => isNumber(v), 181 | }), 182 | ).toBeFalsy(); 183 | expect( 184 | isArray(numberArray, { 185 | valueValidator: (v) => isString(v), 186 | }), 187 | ).toBeFalsy(); 188 | expect( 189 | isArray(symbolArray, { 190 | valueValidator: (v) => isObject(v), 191 | }), 192 | ).toBeFalsy(); 193 | expect( 194 | isArray(recordArray, { 195 | valueValidator: (v) => isSymbol(v), 196 | }), 197 | ).toBeFalsy(); 198 | expect( 199 | isArray([...symbolArray, ...recordArray], { 200 | valueValidator: (v) => 201 | isUnion(isString, isNumber)(v), 202 | }), 203 | ).toBeFalsy(); 204 | }); 205 | it('returns false for non-array values', () => { 206 | expect( 207 | isArray('', { valueValidator: (v) => isString(v) }), 208 | ).toBeFalsy(); 209 | expect( 210 | isArray(null, { valueValidator: (v) => isString(v) }), 211 | ).toBeFalsy(); 212 | expect( 213 | isArray(123, { valueValidator: (v) => isString(v) }), 214 | ).toBeFalsy(); 215 | expect( 216 | isArray(Symbol(), { valueValidator: (v) => isString(v) }), 217 | ).toBeFalsy(); 218 | expect( 219 | isArray({}, { valueValidator: (v) => isString(v) }), 220 | ).toBeFalsy(); 221 | }); 222 | 223 | it('guards type correctly', () => { 224 | const unknownArray: unknown = [...stringArray]; 225 | if ( 226 | isArray(unknownArray, { 227 | valueValidator: (v) => isString(v), 228 | }) 229 | ) { 230 | expect(unknownArray).toEqual(stringArray); 231 | expectTypeOf(unknownArray).toEqualTypeOf(); 232 | } else { 233 | throw new Error('Expected array to pass type guard'); 234 | } 235 | }); 236 | }); 237 | 238 | describe('isSet', () => { 239 | it('returns true for positively tested set values', () => { 240 | expect(isSet(new Set(stringArray))).toBeTruthy(); 241 | expect( 242 | isSet(new Set(stringArray), { 243 | valueValidator: (v) => isString(v), 244 | }), 245 | ).toBeTruthy(); 246 | expect( 247 | isSet(new Set(numberArray), { 248 | valueValidator: (v) => isNumber(v), 249 | }), 250 | ).toBeTruthy(); 251 | expect( 252 | isSet(new Set(symbolArray), { 253 | valueValidator: (v) => isSymbol(v), 254 | }), 255 | ).toBeTruthy(); 256 | expect( 257 | isSet(new Set(recordArray), { 258 | valueValidator: (v) => isObject(v), 259 | }), 260 | ).toBeTruthy(); 261 | expect( 262 | isSet(new Set([...numberArray, ...stringArray]), { 263 | valueValidator: (v) => 264 | isUnion(isString, isNumber)(v), 265 | }), 266 | ).toBeTruthy(); 267 | }); 268 | it('returns false for negatively tested set values', () => { 269 | expect( 270 | isSet(new Set(stringArray), { 271 | valueValidator: (v) => isNumber(v), 272 | }), 273 | ).toBeFalsy(); 274 | expect( 275 | isSet(new Set(numberArray), { 276 | valueValidator: (v) => isString(v), 277 | }), 278 | ).toBeFalsy(); 279 | expect( 280 | isSet(new Set(symbolArray), { 281 | valueValidator: (v) => isObject(v), 282 | }), 283 | ).toBeFalsy(); 284 | expect( 285 | isSet(new Set(recordArray), { 286 | valueValidator: (v) => isSymbol(v), 287 | }), 288 | ).toBeFalsy(); 289 | expect( 290 | isSet(new Set([...recordArray, ...symbolArray]), { 291 | valueValidator: (v) => 292 | isUnion(isString, isNumber)(v), 293 | }), 294 | ).toBeFalsy(); 295 | }); 296 | it('returns false for non-set values', () => { 297 | expect( 298 | isSet('', { valueValidator: (v) => isString(v) }), 299 | ).toBeFalsy(); 300 | expect( 301 | isSet(null, { valueValidator: (v) => isString(v) }), 302 | ).toBeFalsy(); 303 | expect( 304 | isSet(123, { valueValidator: (v) => isString(v) }), 305 | ).toBeFalsy(); 306 | expect( 307 | isSet(Symbol(), { valueValidator: (v) => isString(v) }), 308 | ).toBeFalsy(); 309 | expect( 310 | isSet({}, { valueValidator: (v) => isString(v) }), 311 | ).toBeFalsy(); 312 | }); 313 | it('guards type correctly', () => { 314 | const unknownSet: unknown = new Set(stringArray); 315 | if (isSet(unknownSet)) { 316 | expect([...unknownSet]).toEqual(stringArray); 317 | 318 | const typedSet = unknownSet; 319 | expect(typedSet).toBeInstanceOf(Set); 320 | } 321 | if ( 322 | isSet(unknownSet, { 323 | valueValidator: (v: unknown) => isString(v), 324 | }) 325 | ) { 326 | const typedSet = unknownSet; 327 | expect(typedSet).toBeInstanceOf(Set); 328 | } 329 | }); 330 | }); 331 | 332 | describe('isMap', () => { 333 | it('returns true for positively tested map values', () => { 334 | expect( 335 | isMap(stringMap, { 336 | keyValidator: (v) => isString(v), 337 | valueValidator: (v) => isString(v), 338 | }), 339 | ).toBeTruthy(); 340 | expect( 341 | isMap(numberMap, { 342 | keyValidator: (v) => isNumber(v), 343 | valueValidator: (v) => isNumber(v), 344 | }), 345 | ).toBeTruthy(); 346 | expect( 347 | isMap(symbolMap, { 348 | keyValidator: (v) => isSymbol(v), 349 | valueValidator: (v) => isSymbol(v), 350 | }), 351 | ).toBeTruthy(); 352 | expect( 353 | isMap( 354 | new Map([ 355 | ...stringMap, 356 | ...numberMap, 357 | ...symbolMap, 358 | ]), 359 | { 360 | keyValidator: (v) => 361 | isUnion( 362 | isString, 363 | isNumber, 364 | isSymbol, 365 | )(v), 366 | valueValidator: (v) => 367 | isUnion( 368 | isString, 369 | isNumber, 370 | isSymbol, 371 | )(v), 372 | }, 373 | ), 374 | ).toBeTruthy(); 375 | expect( 376 | isMap( 377 | new Map([ 378 | ...recordMap, 379 | ...booleanMap, 380 | ]), 381 | { 382 | keyValidator: (v) => 383 | isUnion(isObject, isBoolean)(v), 384 | valueValidator: (v) => 385 | isUnion(isObject, isBoolean)(v), 386 | }, 387 | ), 388 | ).toBeTruthy(); 389 | }); 390 | it('returns false for negatively tested map values', () => { 391 | expect( 392 | isMap(stringMap, { 393 | keyValidator: (v: unknown): v is number => isNumber(v), 394 | valueValidator: (v: unknown): v is number => isNumber(v), 395 | }), 396 | ).toBeFalsy(); 397 | expect( 398 | isMap(numberMap, { 399 | keyValidator: (v: unknown): v is string => isString(v), 400 | valueValidator: (v: unknown): v is string => isString(v), 401 | }), 402 | ).toBeFalsy(); 403 | }); 404 | it('returns false for non-map values', () => { 405 | expect(isMap('')).toBeFalsy(); 406 | expect(isMap(true)).toBeFalsy(); 407 | expect(isMap(new Set())).toBeFalsy(); 408 | expect(isMap([])).toBeFalsy(); 409 | expect(isMap(new WeakMap())).toBeFalsy(); 410 | }); 411 | it('guards type correctly', () => { 412 | const unknownMap: unknown = new Map([ 413 | ...recordMap, 414 | ...stringMap, 415 | ]); 416 | if ( 417 | isMap(unknownMap, { 418 | keyValidator: (v) => 419 | isUnion(isObject, isString)(v), 420 | valueValidator: (v) => 421 | isUnion(isObject, isString)(v), 422 | }) 423 | ) { 424 | expect([...unknownMap.entries()]).toEqual( 425 | expect.arrayContaining([...recordMap, ...stringMap]), 426 | ); 427 | 428 | expectTypeOf(unknownMap).toMatchObjectType( 429 | // @ts-ignore 430 | new Map(), 431 | ); 432 | } else { 433 | throw new Error('Expected map to pass type guard'); 434 | } 435 | }); 436 | }); 437 | 438 | describe('isRecord', () => { 439 | it('returns true for positively tested record values', () => { 440 | expect( 441 | isRecord(stringRecord, { 442 | keyValidator: (v) => isString(v), 443 | valueValidator: (v) => isString(v), 444 | }), 445 | ).toBeTruthy(); 446 | expect( 447 | isRecord(numberRecord, { 448 | keyValidator: (v) => isString(v), 449 | valueValidator: (v) => isNumber(v), 450 | }), 451 | ).toBeTruthy(); 452 | expect( 453 | isRecord(symbolRecord, { 454 | keyValidator: (v) => isSymbol(v), 455 | valueValidator: (v) => isSymbol(v), 456 | }), 457 | ).toBeTruthy(); 458 | expect( 459 | isRecord( 460 | { 461 | ...stringRecord, 462 | ...numberRecord, 463 | ...symbolRecord, 464 | }, 465 | { 466 | keyValidator: (v) => 467 | isUnion( 468 | isString, 469 | isNumber, 470 | isSymbol, 471 | )(v), 472 | valueValidator: (v) => 473 | isUnion( 474 | isString, 475 | isNumber, 476 | isSymbol, 477 | )(v), 478 | }, 479 | ), 480 | ).toBeTruthy(); 481 | }); 482 | it('returns false for negatively tested record values', () => { 483 | expect( 484 | isRecord(stringRecord, { 485 | keyValidator: (v: unknown): v is string => isString(v), 486 | valueValidator: (v: unknown): v is number => isNumber(v), 487 | }), 488 | ).toBeFalsy(); 489 | expect( 490 | isRecord(numberRecord, { 491 | keyValidator: (v: unknown): v is string => isString(v), 492 | valueValidator: (v: unknown): v is string => isString(v), 493 | }), 494 | ).toBeFalsy(); 495 | }); 496 | it('returns false for non-record values', () => { 497 | expect(isRecord(CustomClass)).toBeFalsy(); 498 | expect(isRecord(new Map())).toBeFalsy(); 499 | expect(isRecord(new Set())).toBeFalsy(); 500 | expect(isRecord([])).toBeFalsy(); 501 | expect(isRecord(new WeakMap())).toBeFalsy(); 502 | }); 503 | it('guards type correctly', () => { 504 | const unknownRecord: unknown = { 505 | ...numberRecord, 506 | ...stringRecord, 507 | }; 508 | if ( 509 | isRecord(unknownRecord, { 510 | keyValidator: (v) => 511 | isUnion(isNumber, isString)(v), 512 | valueValidator: (v) => 513 | isUnion(isNumber, isString)(v), 514 | }) 515 | ) { 516 | expect(unknownRecord).toMatchObject({ 517 | ...numberRecord, 518 | ...stringRecord, 519 | }); 520 | 521 | // @ts-ignore 522 | expectTypeOf(unknownRecord).toMatchObjectType({ 523 | ...numberRecord, 524 | ...stringRecord, 525 | }); 526 | } else { 527 | throw new Error('Expected record to pass type guard'); 528 | } 529 | }); 530 | }); 531 | 532 | describe.each([ 533 | [ 534 | 'Union', 535 | isUnion(isString, isNumber, isSymbol), 536 | ['abc', 1, Symbol()], 537 | [undefined, true, ...objectValues, ...functionValues], 538 | ], 539 | [ 540 | 'string', 541 | isString, 542 | ['abc'], 543 | [1, true, null, ...objectValues, ...functionValues], 544 | ], 545 | [ 546 | 'number', 547 | isNumber, 548 | [0, 1], 549 | ['abc', true, null, ...objectValues, ...functionValues], 550 | ], 551 | [ 552 | 'bigint', 553 | isBigInt, 554 | [9_007_199_254_740_991n, BigInt(9_007_199_254_740_991)], 555 | [0, 1, 'abc', true, null, ...objectValues, ...functionValues], 556 | ], 557 | [ 558 | 'boolean', 559 | isBoolean, 560 | [true, false], 561 | ['', 0, null, ...objectValues, ...functionValues], 562 | ], 563 | [ 564 | 'symbol', 565 | isSymbol, 566 | [Symbol()], 567 | ['', 0, null, true, ...objectValues, ...functionValues], 568 | ], 569 | [ 570 | 'object', 571 | isObject, 572 | objectValues, 573 | [null, ...primitiveValues, ...functionValues], 574 | ], 575 | [ 576 | 'undefined', 577 | isUndefined, 578 | [undefined], 579 | ['', 0, null, false, ...objectValues, ...functionValues], 580 | ], 581 | [ 582 | 'null', 583 | isNull, 584 | [null], 585 | ['', 0, undefined, false, ...objectValues, ...functionValues], 586 | ], 587 | [ 588 | 'Nullish', 589 | isNullish, 590 | [null, undefined], 591 | ['', 0, false, ...objectValues, ...functionValues], 592 | ], 593 | [ 594 | 'Defined', 595 | isDefined, 596 | ['', 0, null, false, ...objectValues, ...functionValues], 597 | [undefined], 598 | ], 599 | [ 600 | 'notNull', 601 | isNotNull, 602 | ['', 0, undefined, false, ...objectValues, ...functionValues], 603 | [null], 604 | ], 605 | [ 606 | 'notNullish', 607 | isNotNullish, 608 | ['', 0, false, ...objectValues, ...functionValues], 609 | [null, undefined], 610 | ], 611 | [ 612 | 'Error', 613 | isError, 614 | errors, 615 | [ 616 | ...primitiveValues, 617 | ...objectValues.filter((v) => !(v instanceof Error)), 618 | ...functionValues, 619 | ], 620 | ], 621 | [ 622 | 'Buffer', 623 | isBuffer, 624 | [Buffer.alloc(8), Buffer.alloc(16)], 625 | [ 626 | ...primitiveValues, 627 | ...objectValues.filter((v) => !(v instanceof Buffer)), 628 | ...functionValues, 629 | ], 630 | ], 631 | [ 632 | 'ArrayBuffer', 633 | isArrayBuffer, 634 | [new ArrayBuffer(8), new ArrayBuffer(16)], 635 | [ 636 | ...primitiveValues, 637 | ...objectValues.filter((v) => !(v instanceof ArrayBuffer)), 638 | ...functionValues, 639 | ], 640 | ], 641 | [ 642 | 'SharedArrayBuffer', 643 | isSharedArrayBuffer, 644 | [new SharedArrayBuffer(8), new SharedArrayBuffer(16)], 645 | [ 646 | ...primitiveValues, 647 | ...objectValues.filter((v) => !(v instanceof SharedArrayBuffer)), 648 | ...functionValues, 649 | ], 650 | ], 651 | [ 652 | 'AnyArrayBuffer', 653 | isAnyArrayBuffer, 654 | [new SharedArrayBuffer(8), new ArrayBuffer(16)], 655 | [ 656 | ...primitiveValues, 657 | ...objectValues.filter( 658 | (v) => 659 | !(v instanceof SharedArrayBuffer) && 660 | !(v instanceof ArrayBuffer), 661 | ), 662 | ...functionValues, 663 | ], 664 | ], 665 | [ 666 | 'RegExp', 667 | isRegExp, 668 | [new RegExp('test'), /'test'/], 669 | [...primitiveValues, ...objectValues, ...functionValues], 670 | ], 671 | [ 672 | 'Date', 673 | isDate, 674 | [new Date()], 675 | [...primitiveValues, ...objectValues, ...functionValues], 676 | ], 677 | [ 678 | 'String', 679 | isStringObject, 680 | [new String('x')], 681 | [ 682 | ...primitiveValues, 683 | ...objectValues.filter( 684 | (v) => Object.prototype.toString.call(v) !== '[object String]', 685 | ), 686 | ...functionValues, 687 | ], 688 | ], 689 | [ 690 | 'Boolean', 691 | isBooleanObject, 692 | [new Boolean(true)], 693 | [ 694 | ...primitiveValues, 695 | ...objectValues.filter( 696 | (v) => Object.prototype.toString.call(v) !== '[object Boolean]', 697 | ), 698 | ...functionValues, 699 | ], 700 | ], 701 | [ 702 | 'Number', 703 | isNumberObject, 704 | [new Number(1)], 705 | [ 706 | ...primitiveValues, 707 | ...objectValues.filter( 708 | (v) => Object.prototype.toString.call(v) !== '[object Number]', 709 | ), 710 | ...functionValues, 711 | ], 712 | ], 713 | [ 714 | 'Promise', 715 | isPromise, 716 | [promise], 717 | [...objectValues, ...functionValues, ...primitiveValues], 718 | ], 719 | [ 720 | 'Function', 721 | isFunction, 722 | [regularFunction], 723 | [ 724 | asyncFunction, 725 | generatorFunction, 726 | asyncGeneratorFunction, 727 | ...primitiveValues, 728 | ...objectValues, 729 | ], 730 | ], 731 | [ 732 | 'AsyncFunction', 733 | isAsyncFunction, 734 | [asyncFunction], 735 | [ 736 | regularFunction, 737 | generatorFunction, 738 | asyncGeneratorFunction, 739 | ...primitiveValues, 740 | ...objectValues, 741 | ], 742 | ], 743 | [ 744 | 'GeneratorFunction', 745 | isGeneratorFunction, 746 | [generatorFunction], 747 | [ 748 | regularFunction, 749 | asyncFunction, 750 | asyncGeneratorFunction, 751 | ...primitiveValues, 752 | ...objectValues, 753 | ], 754 | ], 755 | [ 756 | 'AsyncGeneratorFunction', 757 | isAsyncGeneratorFunction, 758 | [asyncGeneratorFunction], 759 | [ 760 | regularFunction, 761 | asyncFunction, 762 | generatorFunction, 763 | ...objectValues, 764 | ...primitiveValues, 765 | ], 766 | ], 767 | [ 768 | 'Generator', 769 | isGenerator, 770 | [generator], 771 | [ 772 | asyncGenerator, 773 | ...objectValues, 774 | ...functionValues, 775 | ...primitiveValues, 776 | ], 777 | ], 778 | [ 779 | 'AsyncGenerator', 780 | isAsyncGenerator, 781 | [asyncGenerator], 782 | [generator, ...objectValues, ...functionValues, ...primitiveValues], 783 | ], 784 | [ 785 | 'Iterable', 786 | isIterable, 787 | [...iterableObjects, generator, '', ...typedArrays], 788 | [ 789 | ...errors, 790 | {}, 791 | ...functionValues, 792 | ...primitiveValues.filter((v) => typeof v !== 'string'), 793 | ], 794 | ], 795 | [ 796 | 'AsyncIterable', 797 | isAsyncIterable, 798 | [asyncGenerator], 799 | [...errors, ...typedArrays, {}, ...functionValues, ...primitiveValues], 800 | ], 801 | [ 802 | 'Iterator', 803 | isIterator, 804 | [asyncGenerator, generator, new Map().values(), new Set().values()], 805 | [ 806 | ...errors, 807 | {}, 808 | ...objectValues, 809 | ...typedArrays, 810 | ...functionValues, 811 | ...primitiveValues, 812 | ], 813 | ], 814 | [ 815 | 'TypedArray', 816 | isTypedArray, 817 | typedArrays, 818 | [ 819 | ...objectValues.filter( 820 | (v) => ![...buffers, ...typedArrays].includes(v as any), 821 | ), 822 | ...functionValues, 823 | ...primitiveValues, 824 | ], 825 | ], 826 | [ 827 | 'Int8Array', 828 | isInt8Array, 829 | [new Int8Array()], 830 | [ 831 | ...objectValues.filter( 832 | (v) => ![...buffers, ...typedArrays].includes(v as any), 833 | ), 834 | 835 | ...functionValues, 836 | ...primitiveValues, 837 | ], 838 | ], 839 | [ 840 | 'Uint8Array', 841 | isUint8Array, 842 | [new Uint8Array()], 843 | [ 844 | ...objectValues.filter( 845 | (v) => ![...buffers, ...typedArrays].includes(v as any), 846 | ), 847 | 848 | ...functionValues, 849 | ...primitiveValues, 850 | ], 851 | ], 852 | [ 853 | 'Uint8ClampedArray', 854 | isUint8ClampedArray, 855 | [new Uint8ClampedArray()], 856 | [ 857 | ...objectValues.filter( 858 | (v) => ![...buffers, ...typedArrays].includes(v as any), 859 | ), 860 | 861 | ...functionValues, 862 | ...primitiveValues, 863 | ], 864 | ], 865 | [ 866 | 'Int16Array', 867 | isInt16Array, 868 | [new Int16Array()], 869 | [ 870 | ...objectValues.filter( 871 | (v) => ![...buffers, ...typedArrays].includes(v as any), 872 | ), 873 | 874 | ...functionValues, 875 | ...primitiveValues, 876 | ], 877 | ], 878 | [ 879 | 'Uint16Array', 880 | isUint16Array, 881 | [new Uint16Array()], 882 | [ 883 | ...objectValues.filter( 884 | (v) => ![...buffers, ...typedArrays].includes(v as any), 885 | ), 886 | 887 | ...functionValues, 888 | ...primitiveValues, 889 | ], 890 | ], 891 | [ 892 | 'Int32Array', 893 | isInt32Array, 894 | [new Int32Array()], 895 | [ 896 | ...objectValues.filter( 897 | (v) => ![...buffers, ...typedArrays].includes(v as any), 898 | ), 899 | 900 | ...functionValues, 901 | ...primitiveValues, 902 | ], 903 | ], 904 | [ 905 | 'Uint32Array', 906 | isUint32Array, 907 | [new Uint32Array()], 908 | [ 909 | ...objectValues.filter( 910 | (v) => ![...buffers, ...typedArrays].includes(v as any), 911 | ), 912 | 913 | ...functionValues, 914 | ...primitiveValues, 915 | ], 916 | ], 917 | [ 918 | 'Float32Array', 919 | isFloat32Array, 920 | [new Float32Array()], 921 | [ 922 | ...objectValues.filter( 923 | (v) => ![...buffers, ...typedArrays].includes(v as any), 924 | ), 925 | 926 | ...functionValues, 927 | ...primitiveValues, 928 | ], 929 | ], 930 | [ 931 | 'Float64Array', 932 | isFloat64Array, 933 | [new Float64Array()], 934 | [ 935 | ...objectValues.filter( 936 | (v) => ![...buffers, ...typedArrays].includes(v as any), 937 | ), 938 | 939 | ...functionValues, 940 | ...primitiveValues, 941 | ], 942 | ], 943 | [ 944 | 'BigInt64Array', 945 | isBigInt64Array, 946 | [new BigInt64Array()], 947 | [ 948 | ...objectValues.filter( 949 | (v) => ![...buffers, ...typedArrays].includes(v as any), 950 | ), 951 | 952 | ...functionValues, 953 | ...primitiveValues, 954 | ], 955 | ], 956 | [ 957 | 'BigUint64Array', 958 | isBigUint64Array, 959 | [new BigUint64Array()], 960 | [ 961 | ...objectValues.filter( 962 | (v) => ![...buffers, ...typedArrays].includes(v as any), 963 | ), 964 | 965 | ...functionValues, 966 | ...primitiveValues, 967 | ], 968 | ], 969 | [ 970 | 'DataView', 971 | isDataView, 972 | [new DataView(new ArrayBuffer(8))], 973 | [...objectValues, ...primitiveValues, ...functionValues], 974 | ], 975 | [ 976 | 'WeakMap', 977 | isWeakMap, 978 | [new WeakMap([[stringRecord, '123']])], 979 | [ 980 | ...objectValues.filter((v) => !(v instanceof WeakMap)), 981 | ...primitiveValues, 982 | ...functionValues, 983 | ], 984 | ], 985 | [ 986 | 'WeakSet', 987 | isWeakSet, 988 | [new WeakSet([stringRecord, numberRecord])], 989 | [ 990 | ...objectValues.filter((v) => !(v instanceof WeakSet)), 991 | ...primitiveValues, 992 | ...functionValues, 993 | ], 994 | ], 995 | [ 996 | 'PlainObject', 997 | isPlainObject, 998 | [ 999 | {}, 1000 | { a: 1 }, 1001 | Object.create(null), 1002 | Object.create(Object.prototype), 1003 | Object.create(Object.create(null)), 1004 | ], 1005 | [ 1006 | new Date(), 1007 | [], 1008 | null, 1009 | undefined, 1010 | new CustomClass(), 1011 | ...functionValues, 1012 | ...primitiveValues.filter( 1013 | (v): v is boolean | number | string | symbol => 1014 | Boolean(v) || v === false || v === 0 || v === '', 1015 | ), 1016 | ], 1017 | ], 1018 | [ 1019 | 'ArgumentsObject', 1020 | isArgumentsObject, 1021 | [ 1022 | (function () { 1023 | // @ts-ignore 1024 | return arguments; 1025 | // @ts-ignore 1026 | })(1, 2, 3), 1027 | ], 1028 | [{}, [], null, undefined, ...functionValues, ...primitiveValues], 1029 | ], 1030 | [ 1031 | 'ArrayBufferView', 1032 | isArrayBufferView, 1033 | [ 1034 | new Uint8Array(), 1035 | new Uint16Array(), 1036 | new Uint32Array(), 1037 | new Int8Array(), 1038 | new Int16Array(), 1039 | new Int32Array(), 1040 | new Float32Array(), 1041 | new Float64Array(), 1042 | new DataView(new ArrayBuffer(8)), 1043 | ], 1044 | [ 1045 | new ArrayBuffer(8), 1046 | [], 1047 | {}, 1048 | null, 1049 | undefined, 1050 | ...functionValues, 1051 | ...primitiveValues, 1052 | ], 1053 | ], 1054 | [ 1055 | 'BigIntObject', 1056 | isBigIntObject, 1057 | [new Object(BigInt(123))], 1058 | [ 1059 | BigInt(123), 1060 | 123, 1061 | '123', 1062 | null, 1063 | undefined, 1064 | ...objectValues.filter( 1065 | (v) => 1066 | !(Object.prototype.toString.call(v) === '[object BigInt]'), 1067 | ), 1068 | ...functionValues, 1069 | ], 1070 | ], 1071 | [ 1072 | 'BoxedPrimitive', 1073 | isBoxedPrimitive, 1074 | [ 1075 | new Object('string'), 1076 | new Object(123), 1077 | new Object(true), 1078 | new Object(Symbol('test')), 1079 | new Object(BigInt(123)), 1080 | ], 1081 | [ 1082 | 'string', 1083 | 123, 1084 | true, 1085 | Symbol('test'), 1086 | BigInt(123), 1087 | null, 1088 | undefined, 1089 | {}, 1090 | [], 1091 | ...functionValues, 1092 | ], 1093 | ], 1094 | [ 1095 | 'EmptyArray', 1096 | isEmptyArray, 1097 | [[]], 1098 | [ 1099 | [1], 1100 | ['a'], 1101 | {}, 1102 | '', 1103 | null, 1104 | undefined, 1105 | ...objectValues.filter((v) => !Array.isArray(v)), 1106 | ...functionValues, 1107 | ], 1108 | ], 1109 | [ 1110 | 'EmptyObject', 1111 | isEmptyObject, 1112 | [{}], 1113 | [ 1114 | { a: 1 }, 1115 | [], 1116 | '', 1117 | null, 1118 | undefined, 1119 | ...objectValues.filter((v) => Object.keys(v as object).length > 0), 1120 | ...functionValues, 1121 | ], 1122 | ], 1123 | [ 1124 | 'EmptyString', 1125 | isEmptyString, 1126 | [''], 1127 | [ 1128 | 'a', 1129 | ' ', 1130 | [], 1131 | {}, 1132 | null, 1133 | undefined, 1134 | ...objectValues.filter((v) => typeof v !== 'string'), 1135 | ...functionValues, 1136 | ], 1137 | ], 1138 | [ 1139 | 'Finite', 1140 | isFinite, 1141 | [0, 1, -1, 1.5, Number.MAX_VALUE, -Number.MAX_VALUE], 1142 | [ 1143 | Infinity, 1144 | -Infinity, 1145 | Number.NaN, 1146 | '1', 1147 | true, 1148 | null, 1149 | undefined, 1150 | ...objectValues, 1151 | ...functionValues, 1152 | ], 1153 | ], 1154 | [ 1155 | 'Integer', 1156 | isInteger, 1157 | [0, 1, -1, Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER], 1158 | [1.5, '1', true, null, undefined, ...objectValues, ...functionValues], 1159 | ], 1160 | [ 1161 | 'MapIterator', 1162 | isMapIterator, 1163 | [new Map().entries()], 1164 | [ 1165 | new Map(), 1166 | new Set(), 1167 | [], 1168 | {}, 1169 | null, 1170 | undefined, 1171 | ...functionValues, 1172 | ...primitiveValues, 1173 | ], 1174 | ], 1175 | [ 1176 | 'NaN', 1177 | isNaN, 1178 | [Number.NaN, Number.NaN], 1179 | [0, 'NaN', null, undefined, ...objectValues, ...functionValues], 1180 | ], 1181 | [ 1182 | 'NativeError', 1183 | isNativeError, 1184 | [new Error(), new TypeError(), new RangeError()], 1185 | [ 1186 | { message: 'error', name: 'Error' }, 1187 | null, 1188 | undefined, 1189 | ...objectValues.filter((v) => !(v instanceof Error)), 1190 | ...functionValues, 1191 | ], 1192 | ], 1193 | [ 1194 | 'NonEmptyArray', 1195 | isNonEmptyArray, 1196 | [[1], ['a'], [{}], [null], [undefined]], 1197 | [ 1198 | [], 1199 | {}, 1200 | '', 1201 | null, 1202 | undefined, 1203 | ...objectValues.filter((v) => !Array.isArray(v)), 1204 | ...functionValues, 1205 | ], 1206 | ], 1207 | [ 1208 | 'NonEmptyString', 1209 | isNonEmptyString, 1210 | ['a', ' ', 'test', '0', 'false'], 1211 | [ 1212 | '', 1213 | [], 1214 | {}, 1215 | null, 1216 | undefined, 1217 | ...objectValues.filter((v) => typeof v !== 'string'), 1218 | ...functionValues, 1219 | ], 1220 | ], 1221 | [ 1222 | 'SafeInteger', 1223 | isSafeInteger, 1224 | [0, 1, -1, Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER], 1225 | [ 1226 | Number.MAX_SAFE_INTEGER + 1, 1227 | -Number.MAX_SAFE_INTEGER - 1, 1228 | 1.5, 1229 | '1', 1230 | true, 1231 | null, 1232 | undefined, 1233 | ...objectValues, 1234 | ...functionValues, 1235 | ], 1236 | ], 1237 | [ 1238 | 'SetIterator', 1239 | isSetIterator, 1240 | [new Set().values()], 1241 | [ 1242 | new Set(), 1243 | new Map(), 1244 | [], 1245 | {}, 1246 | null, 1247 | undefined, 1248 | ...functionValues, 1249 | ...primitiveValues, 1250 | ], 1251 | ], 1252 | [ 1253 | 'SymbolObject', 1254 | isSymbolObject, 1255 | [new Object(Symbol('test'))], 1256 | [ 1257 | Symbol('test'), 1258 | 'symbol', 1259 | {}, 1260 | [], 1261 | null, 1262 | undefined, 1263 | ...objectValues.filter( 1264 | (v) => 1265 | !(Object.prototype.toString.call(v) === '[object Symbol]'), 1266 | ), 1267 | ...functionValues, 1268 | ], 1269 | ], 1270 | ])( 1271 | '%s', 1272 | ( 1273 | _: string, 1274 | guard: TypeGuard, 1275 | expected: unknown[], 1276 | failed: unknown[], 1277 | ) => { 1278 | it.each(expected.map((v) => [v]))( 1279 | `returns true for expected values`, 1280 | (value) => { 1281 | expect(guard(value)).toBeTruthy(); 1282 | }, 1283 | ); 1284 | it.each(failed.map((v) => [v]))( 1285 | `returns false for non-expected values`, 1286 | (value) => { 1287 | expect(guard(value)).toBeFalsy(); 1288 | }, 1289 | ); 1290 | }, 1291 | ); 1292 | -------------------------------------------------------------------------------- /tests/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTypeGuard, isUnion } from '../src'; 2 | 3 | // eslint-disable-next-line @typescript-eslint/no-extraneous-class 4 | class CustomClass {} 5 | const customTypeGuard = createTypeGuard( 6 | (value) => value instanceof CustomClass, 7 | ); 8 | 9 | describe('createTypeGuard', () => { 10 | it('creates a type-guard', () => { 11 | expect(customTypeGuard(new CustomClass())).toBeTruthy(); 12 | }); 13 | it('creates a type-guard with options', () => { 14 | const mock = vi.fn( 15 | (value: unknown): value is CustomClass => 16 | value instanceof CustomClass, 17 | ); 18 | const options = { valueValidator: mock }; 19 | const typeGuard = createTypeGuard< 20 | CustomClass, 21 | { valueValidator: (value: unknown) => value is CustomClass } 22 | >((value, opts) => { 23 | if (!(value instanceof CustomClass)) { 24 | return false; 25 | } 26 | // @ts-ignore - optional property access 27 | if (opts?.valueValidator) { 28 | // @ts-ignore - optional property access 29 | return opts.valueValidator(value); 30 | } 31 | return true; 32 | // @ts-ignore 33 | }, options); 34 | const testValue = new CustomClass(); 35 | expect(typeGuard(testValue)).toBe(true); 36 | expect(mock).toHaveBeenCalledWith(testValue); 37 | }); 38 | }); 39 | 40 | describe('isUnion', () => { 41 | it('creates a union type guard', () => { 42 | const isString = (v: unknown): v is string => typeof v === 'string'; 43 | 44 | const isNumber = (v: unknown): v is number => typeof v === 'number'; 45 | 46 | const guard = isUnion(isString, isNumber); 47 | 48 | expect(guard('test')).toBe(true); 49 | expect(guard(123)).toBe(true); 50 | expect(guard(true)).toBe(false); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "compilerOptions": { 4 | "alwaysStrict": true, 5 | "baseUrl": ".", 6 | "esModuleInterop": true, 7 | "inlineSourceMap": true, 8 | "module": "CommonJS", 9 | "noImplicitAny": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "skipLibCheck": true, 13 | "strict": true, 14 | "strictFunctionTypes": true, 15 | "strictNullChecks": true, 16 | "target": "ESNext", 17 | "resolveJsonModule": true, 18 | "allowSyntheticDefaultImports": true, 19 | "forceConsistentCasingInFileNames": true, 20 | "incremental": true, 21 | "strictBindCallApply": true, 22 | "strictPropertyInitialization": true, 23 | "types": ["vitest/globals", "vitest"] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | import { PackageJson } from 'type-fest'; 4 | import { defineConfig } from 'vite'; 5 | import dts from 'vite-plugin-dts'; 6 | 7 | import manifest from './package.json'; 8 | 9 | const { name } = manifest as PackageJson; 10 | export default defineConfig({ 11 | build: { 12 | lib: { 13 | entry: path.resolve(__dirname, 'src/index.ts'), 14 | fileName: (format) => `index.${format === 'es' ? 'mjs' : 'js'}`, 15 | formats: ['es', 'cjs'], 16 | name, 17 | }, 18 | minify: true, 19 | rollupOptions: { 20 | output: { 21 | preserveModules: false, 22 | }, 23 | }, 24 | sourcemap: true, 25 | target: 'es2020', 26 | }, 27 | plugins: [dts({ rollupTypes: true })], 28 | test: { 29 | coverage: { 30 | exclude: ['node_modules/**', 'dist/**'], 31 | reporter: ['text', 'lcov'], 32 | }, 33 | globals: true, 34 | include: ['tests/**/*.spec.ts'], 35 | }, 36 | }); 37 | --------------------------------------------------------------------------------