├── .editorconfig ├── .gitattributes ├── .github ├── security.md └── workflows │ └── main.yml ├── .gitignore ├── .npmrc ├── header.gif ├── license ├── package.json ├── readme.md ├── source ├── index.ts └── types.ts ├── test └── test.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. 4 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | test: 7 | name: Node.js ${{ matrix.node-version }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | node-version: 13 | - 20 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-node@v4 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - run: npm install 20 | - run: npm test 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | /distribution 4 | .tsimp 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /header.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/is/e0976457e04ba5df210ca0c976844b580b62f741/header.gif -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sindresorhus/is", 3 | "version": "7.0.1", 4 | "description": "Type check values", 5 | "license": "MIT", 6 | "repository": "sindresorhus/is", 7 | "funding": "https://github.com/sindresorhus/is?sponsor=1", 8 | "author": { 9 | "name": "Sindre Sorhus", 10 | "email": "sindresorhus@gmail.com", 11 | "url": "https://sindresorhus.com" 12 | }, 13 | "type": "module", 14 | "exports": { 15 | "types": "./distribution/index.d.ts", 16 | "default": "./distribution/index.js" 17 | }, 18 | "sideEffects": false, 19 | "engines": { 20 | "node": ">=18" 21 | }, 22 | "scripts": { 23 | "build": "del distribution && tsc", 24 | "test": "tsc --noEmit && xo && ava", 25 | "prepare": "npm run build" 26 | }, 27 | "files": [ 28 | "distribution" 29 | ], 30 | "keywords": [ 31 | "type", 32 | "types", 33 | "is", 34 | "check", 35 | "checking", 36 | "validate", 37 | "validation", 38 | "utility", 39 | "util", 40 | "typeof", 41 | "instanceof", 42 | "object", 43 | "assert", 44 | "assertion", 45 | "test", 46 | "kind", 47 | "primitive", 48 | "verify", 49 | "compare", 50 | "typescript", 51 | "typeguards", 52 | "types" 53 | ], 54 | "devDependencies": { 55 | "@sindresorhus/tsconfig": "^6.0.0", 56 | "@types/jsdom": "^21.1.7", 57 | "@types/node": "^20.14.10", 58 | "@types/zen-observable": "^0.8.7", 59 | "ava": "^6.1.3", 60 | "del-cli": "^5.1.0", 61 | "expect-type": "^0.19.0", 62 | "jsdom": "^24.1.0", 63 | "rxjs": "^7.8.1", 64 | "tempy": "^3.1.0", 65 | "tsimp": "^2.0.11", 66 | "typescript": "^5.5.3", 67 | "xo": "^0.58.0", 68 | "zen-observable": "^0.10.0" 69 | }, 70 | "ava": { 71 | "environmentVariables": { 72 | "TSIMP_DIAG": "error" 73 | }, 74 | "extensions": { 75 | "ts": "module" 76 | }, 77 | "nodeArguments": [ 78 | "--import=tsimp/import" 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # is 2 | 3 | > Type check values 4 | 5 | For example, `is.string('🦄') //=> true` 6 | 7 | 8 | 9 | ## Highlights 10 | 11 | - Written in TypeScript 12 | - [Extensive use of type guards](#type-guards) 13 | - [Supports type assertions](#type-assertions) 14 | - [Aware of generic type parameters](#generic-type-parameters) (use with caution) 15 | - Actively maintained 16 | - ![Millions of downloads per week](https://img.shields.io/npm/dw/@sindresorhus/is) 17 | 18 | ## Install 19 | 20 | ```sh 21 | npm install @sindresorhus/is 22 | ``` 23 | 24 | ## Usage 25 | 26 | ```js 27 | import is from '@sindresorhus/is'; 28 | 29 | is('🦄'); 30 | //=> 'string' 31 | 32 | is(new Map()); 33 | //=> 'Map' 34 | 35 | is.number(6); 36 | //=> true 37 | ``` 38 | 39 | [Assertions](#type-assertions) perform the same type checks, but throw an error if the type does not match. 40 | 41 | ```js 42 | import {assert} from '@sindresorhus/is'; 43 | 44 | assert.string(2); 45 | //=> Error: Expected value which is `string`, received value of type `number`. 46 | ``` 47 | 48 | Assertions (except `assertAll` and `assertAny`) also support an optional custom error message. 49 | 50 | ```js 51 | import {assert} from '@sindresorhus/is'; 52 | 53 | assert.nonEmptyString(process.env.API_URL, 'The API_URL environment variable is required.'); 54 | //=> Error: The API_URL environment variable is required. 55 | ``` 56 | 57 | And with TypeScript: 58 | 59 | ```ts 60 | import {assert} from '@sindresorhus/is'; 61 | 62 | assert.string(foo); 63 | // `foo` is now typed as a `string`. 64 | ``` 65 | 66 | ### Named exports 67 | 68 | Named exports allow tooling to perform tree-shaking, potentially reducing bundle size by including only code from the methods that are used. 69 | 70 | Every method listed below is available as a named export. Each method is prefixed by either `is` or `assert` depending on usage. 71 | 72 | For example: 73 | 74 | ```js 75 | import {assertNull, isUndefined} from '@sindresorhus/is'; 76 | ``` 77 | 78 | ## API 79 | 80 | ### is(value) 81 | 82 | Returns the type of `value`. 83 | 84 | Primitives are lowercase and object types are camelcase. 85 | 86 | Example: 87 | 88 | - `'undefined'` 89 | - `'null'` 90 | - `'string'` 91 | - `'symbol'` 92 | - `'Array'` 93 | - `'Function'` 94 | - `'Object'` 95 | 96 | This method is also exported as `detect`. You can import it like this: 97 | 98 | ```js 99 | import {detect} from '@sindresorhus/is'; 100 | ``` 101 | 102 | Note: It will throw an error if you try to feed it object-wrapped primitives, as that's a bad practice. For example `new String('foo')`. 103 | 104 | ### is.{method} 105 | 106 | All the below methods accept a value and return a boolean for whether the value is of the desired type. 107 | 108 | #### Primitives 109 | 110 | ##### .undefined(value) 111 | ##### .null(value) 112 | 113 | ##### .string(value) 114 | ##### .number(value) 115 | 116 | Note: `is.number(NaN)` returns `false`. This intentionally deviates from `typeof` behavior to increase user-friendliness of `is` type checks. 117 | 118 | ##### .boolean(value) 119 | ##### .symbol(value) 120 | ##### .bigint(value) 121 | 122 | #### Built-in types 123 | 124 | ##### .array(value, assertion?) 125 | 126 | Returns true if `value` is an array and all of its items match the assertion (if provided). 127 | 128 | ```js 129 | is.array(value); // Validate `value` is an array. 130 | is.array(value, is.number); // Validate `value` is an array and all of its items are numbers. 131 | ``` 132 | 133 | ##### .function(value) 134 | 135 | ##### .buffer(value) 136 | 137 | > [!NOTE] 138 | > [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) 139 | 140 | ##### .blob(value) 141 | ##### .object(value) 142 | 143 | Keep in mind that [functions are objects too](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions). 144 | 145 | ##### .numericString(value) 146 | 147 | Returns `true` for a string that represents a number satisfying `is.number`, for example, `'42'` and `'-8.3'`. 148 | 149 | Note: `'NaN'` returns `false`, but `'Infinity'` and `'-Infinity'` return `true`. 150 | 151 | ##### .regExp(value) 152 | ##### .date(value) 153 | ##### .error(value) 154 | ##### .nativePromise(value) 155 | ##### .promise(value) 156 | 157 | Returns `true` for any object with a `.then()` and `.catch()` method. Prefer this one over `.nativePromise()` as you usually want to allow userland promise implementations too. 158 | 159 | ##### .generator(value) 160 | 161 | Returns `true` for any object that implements its own `.next()` and `.throw()` methods and has a function definition for `Symbol.iterator`. 162 | 163 | ##### .generatorFunction(value) 164 | 165 | ##### .asyncFunction(value) 166 | 167 | Returns `true` for any `async` function that can be called with the `await` operator. 168 | 169 | ```js 170 | is.asyncFunction(async () => {}); 171 | //=> true 172 | 173 | is.asyncFunction(() => {}); 174 | //=> false 175 | ``` 176 | 177 | ##### .asyncGenerator(value) 178 | 179 | ```js 180 | is.asyncGenerator( 181 | (async function * () { 182 | yield 4; 183 | })() 184 | ); 185 | //=> true 186 | 187 | is.asyncGenerator( 188 | (function * () { 189 | yield 4; 190 | })() 191 | ); 192 | //=> false 193 | ``` 194 | 195 | ##### .asyncGeneratorFunction(value) 196 | 197 | ```js 198 | is.asyncGeneratorFunction(async function * () { 199 | yield 4; 200 | }); 201 | //=> true 202 | 203 | is.asyncGeneratorFunction(function * () { 204 | yield 4; 205 | }); 206 | //=> false 207 | ``` 208 | 209 | ##### .boundFunction(value) 210 | 211 | Returns `true` for any `bound` function. 212 | 213 | ```js 214 | is.boundFunction(() => {}); 215 | //=> true 216 | 217 | is.boundFunction(function () {}.bind(null)); 218 | //=> true 219 | 220 | is.boundFunction(function () {}); 221 | //=> false 222 | ``` 223 | 224 | ##### .map(value) 225 | ##### .set(value) 226 | ##### .weakMap(value) 227 | ##### .weakSet(value) 228 | ##### .weakRef(value) 229 | 230 | #### Typed arrays 231 | 232 | ##### .int8Array(value) 233 | ##### .uint8Array(value) 234 | ##### .uint8ClampedArray(value) 235 | ##### .int16Array(value) 236 | ##### .uint16Array(value) 237 | ##### .int32Array(value) 238 | ##### .uint32Array(value) 239 | ##### .float32Array(value) 240 | ##### .float64Array(value) 241 | ##### .bigInt64Array(value) 242 | ##### .bigUint64Array(value) 243 | 244 | #### Structured data 245 | 246 | ##### .arrayBuffer(value) 247 | ##### .sharedArrayBuffer(value) 248 | ##### .dataView(value) 249 | 250 | ##### .enumCase(value, enum) 251 | 252 | TypeScript-only. Returns `true` if `value` is a member of `enum`. 253 | 254 | ```ts 255 | enum Direction { 256 | Ascending = 'ascending', 257 | Descending = 'descending' 258 | } 259 | 260 | is.enumCase('ascending', Direction); 261 | //=> true 262 | 263 | is.enumCase('other', Direction); 264 | //=> false 265 | ``` 266 | 267 | #### Emptiness 268 | 269 | ##### .emptyString(value) 270 | 271 | Returns `true` if the value is a `string` and the `.length` is 0. 272 | 273 | ##### .emptyStringOrWhitespace(value) 274 | 275 | Returns `true` if `is.emptyString(value)` or if it's a `string` that is all whitespace. 276 | 277 | ##### .nonEmptyString(value) 278 | 279 | Returns `true` if the value is a `string` and the `.length` is more than 0. 280 | 281 | ##### .nonEmptyStringAndNotWhitespace(value) 282 | 283 | Returns `true` if the value is a `string` that is not empty and not whitespace. 284 | 285 | ```js 286 | const values = ['property1', '', null, 'property2', ' ', undefined]; 287 | 288 | values.filter(is.nonEmptyStringAndNotWhitespace); 289 | //=> ['property1', 'property2'] 290 | ``` 291 | 292 | ##### .emptyArray(value) 293 | 294 | Returns `true` if the value is an `Array` and the `.length` is 0. 295 | 296 | ##### .nonEmptyArray(value) 297 | 298 | Returns `true` if the value is an `Array` and the `.length` is more than 0. 299 | 300 | ##### .emptyObject(value) 301 | 302 | Returns `true` if the value is an `Object` and `Object.keys(value).length` is 0. 303 | 304 | Please note that `Object.keys` returns only own enumerable properties. Hence something like this can happen: 305 | 306 | ```js 307 | const object1 = {}; 308 | 309 | Object.defineProperty(object1, 'property1', { 310 | value: 42, 311 | writable: true, 312 | enumerable: false, 313 | configurable: true 314 | }); 315 | 316 | is.emptyObject(object1); 317 | //=> true 318 | ``` 319 | 320 | ##### .nonEmptyObject(value) 321 | 322 | Returns `true` if the value is an `Object` and `Object.keys(value).length` is more than 0. 323 | 324 | ##### .emptySet(value) 325 | 326 | Returns `true` if the value is a `Set` and the `.size` is 0. 327 | 328 | ##### .nonEmptySet(Value) 329 | 330 | Returns `true` if the value is a `Set` and the `.size` is more than 0. 331 | 332 | ##### .emptyMap(value) 333 | 334 | Returns `true` if the value is a `Map` and the `.size` is 0. 335 | 336 | ##### .nonEmptyMap(value) 337 | 338 | Returns `true` if the value is a `Map` and the `.size` is more than 0. 339 | 340 | #### Miscellaneous 341 | 342 | ##### .directInstanceOf(value, class) 343 | 344 | Returns `true` if `value` is a direct instance of `class`. 345 | 346 | ```js 347 | is.directInstanceOf(new Error(), Error); 348 | //=> true 349 | 350 | class UnicornError extends Error {} 351 | 352 | is.directInstanceOf(new UnicornError(), Error); 353 | //=> false 354 | ``` 355 | 356 | ##### .urlInstance(value) 357 | 358 | Returns `true` if `value` is an instance of the [`URL` class](https://developer.mozilla.org/en-US/docs/Web/API/URL). 359 | 360 | ```js 361 | const url = new URL('https://example.com'); 362 | 363 | is.urlInstance(url); 364 | //=> true 365 | ``` 366 | 367 | ##### .urlString(value) 368 | 369 | Returns `true` if `value` is a URL string. 370 | 371 | Note: this only does basic checking using the [`URL` class](https://developer.mozilla.org/en-US/docs/Web/API/URL) constructor. 372 | 373 | ```js 374 | const url = 'https://example.com'; 375 | 376 | is.urlString(url); 377 | //=> true 378 | 379 | is.urlString(new URL(url)); 380 | //=> false 381 | ``` 382 | 383 | ##### .truthy(value) 384 | 385 | Returns `true` for all values that evaluate to true in a boolean context: 386 | 387 | ```js 388 | is.truthy('🦄'); 389 | //=> true 390 | 391 | is.truthy(undefined); 392 | //=> false 393 | ``` 394 | 395 | ##### .falsy(value) 396 | 397 | Returns `true` if `value` is one of: `false`, `0`, `''`, `null`, `undefined`, `NaN`. 398 | 399 | ##### .nan(value) 400 | ##### .nullOrUndefined(value) 401 | ##### .primitive(value) 402 | 403 | JavaScript primitives are as follows: 404 | 405 | - `null` 406 | - `undefined` 407 | - `string` 408 | - `number` 409 | - `boolean` 410 | - `symbol` 411 | - `bigint` 412 | 413 | ##### .integer(value) 414 | 415 | ##### .safeInteger(value) 416 | 417 | Returns `true` if `value` is a [safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger). 418 | 419 | ##### .plainObject(value) 420 | 421 | An object is plain if it's created by either `{}`, `new Object()`, or `Object.create(null)`. 422 | 423 | ##### .iterable(value) 424 | ##### .asyncIterable(value) 425 | ##### .class(value) 426 | 427 | Returns `true` if the value is a class constructor. 428 | 429 | ##### .typedArray(value) 430 | 431 | ##### .arrayLike(value) 432 | 433 | A `value` is array-like if it is not a function and has a `value.length` that is a safe integer greater than or equal to 0. 434 | 435 | ```js 436 | is.arrayLike(document.forms); 437 | //=> true 438 | 439 | function foo() { 440 | is.arrayLike(arguments); 441 | //=> true 442 | } 443 | foo(); 444 | ``` 445 | 446 | ##### .tupleLike(value, guards) 447 | 448 | A `value` is tuple-like if it matches the provided `guards` array both in `.length` and in types. 449 | 450 | ```js 451 | is.tupleLike([1], [is.number]); 452 | //=> true 453 | ``` 454 | 455 | ```js 456 | function foo() { 457 | const tuple = [1, '2', true]; 458 | if (is.tupleLike(tuple, [is.number, is.string, is.boolean])) { 459 | tuple // [number, string, boolean] 460 | } 461 | } 462 | 463 | foo(); 464 | ``` 465 | 466 | ##### .positiveNumber(value) 467 | 468 | Check if `value` is a number and is more than 0. 469 | 470 | ##### .negativeNumber(value) 471 | 472 | Check if `value` is a number and is less than 0. 473 | 474 | ##### .inRange(value, range) 475 | 476 | Check if `value` (number) is in the given `range`. The range is an array of two values, lower bound and upper bound, in no specific order. 477 | 478 | ```js 479 | is.inRange(3, [0, 5]); 480 | is.inRange(3, [5, 0]); 481 | is.inRange(0, [-2, 2]); 482 | ``` 483 | 484 | ##### .inRange(value, upperBound) 485 | 486 | Check if `value` (number) is in the range of `0` to `upperBound`. 487 | 488 | ```js 489 | is.inRange(3, 10); 490 | ``` 491 | 492 | ##### .htmlElement(value) 493 | 494 | Returns `true` if `value` is an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). 495 | 496 | ##### .nodeStream(value) 497 | 498 | Returns `true` if `value` is a Node.js [stream](https://nodejs.org/api/stream.html). 499 | 500 | ```js 501 | import fs from 'node:fs'; 502 | 503 | is.nodeStream(fs.createReadStream('unicorn.png')); 504 | //=> true 505 | ``` 506 | 507 | ##### .observable(value) 508 | 509 | Returns `true` if `value` is an `Observable`. 510 | 511 | ```js 512 | import {Observable} from 'rxjs'; 513 | 514 | is.observable(new Observable()); 515 | //=> true 516 | ``` 517 | 518 | ##### .infinite(value) 519 | 520 | Check if `value` is `Infinity` or `-Infinity`. 521 | 522 | ##### .evenInteger(value) 523 | 524 | Returns `true` if `value` is an even integer. 525 | 526 | ##### .oddInteger(value) 527 | 528 | Returns `true` if `value` is an odd integer. 529 | 530 | ##### .propertyKey(value) 531 | 532 | Returns `true` if `value` can be used as an object property key (either `string`, `number`, or `symbol`). 533 | 534 | ##### .formData(value) 535 | 536 | Returns `true` if `value` is an instance of the [`FormData` class](https://developer.mozilla.org/en-US/docs/Web/API/FormData). 537 | 538 | ```js 539 | const data = new FormData(); 540 | 541 | is.formData(data); 542 | //=> true 543 | ``` 544 | 545 | ##### .urlSearchParams(value) 546 | 547 | Returns `true` if `value` is an instance of the [`URLSearchParams` class](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). 548 | 549 | ```js 550 | const searchParams = new URLSearchParams(); 551 | 552 | is.urlSearchParams(searchParams); 553 | //=> true 554 | ``` 555 | 556 | ##### .any(predicate | predicate[], ...values) 557 | 558 | Using a single `predicate` argument, returns `true` if **any** of the input `values` returns true in the `predicate`: 559 | 560 | ```js 561 | is.any(is.string, {}, true, '🦄'); 562 | //=> true 563 | 564 | is.any(is.boolean, 'unicorns', [], new Map()); 565 | //=> false 566 | ``` 567 | 568 | Using an array of `predicate[]`, returns `true` if **any** of the input `values` returns true for **any** of the `predicates` provided in an array: 569 | 570 | ```js 571 | is.any([is.string, is.number], {}, true, '🦄'); 572 | //=> true 573 | 574 | is.any([is.boolean, is.number], 'unicorns', [], new Map()); 575 | //=> false 576 | ``` 577 | 578 | ##### .all(predicate, ...values) 579 | 580 | Returns `true` if **all** of the input `values` returns true in the `predicate`: 581 | 582 | ```js 583 | is.all(is.object, {}, new Map(), new Set()); 584 | //=> true 585 | 586 | is.all(is.string, '🦄', [], 'unicorns'); 587 | //=> false 588 | ``` 589 | 590 | ##### .validDate(value) 591 | 592 | Returns `true` if the value is a valid date. 593 | 594 | All [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date) objects have an internal timestamp value which is the number of milliseconds since the [Unix epoch](https://developer.mozilla.org/en-US/docs/Glossary/Unix_time). When a new `Date` is constructed with bad inputs, no error is thrown. Instead, a new `Date` object is returned. But the internal timestamp value is set to `NaN`, which is an `'Invalid Date'`. Bad inputs can be an non-parsable date string, a non-numeric value or a number that is outside of the expected range for a date value. 595 | 596 | ```js 597 | const valid = new Date('2000-01-01'); 598 | 599 | is.date(valid); 600 | //=> true 601 | valid.getTime(); 602 | //=> 946684800000 603 | valid.toUTCString(); 604 | //=> 'Sat, 01 Jan 2000 00:00:00 GMT' 605 | is.validDate(valid); 606 | //=> true 607 | 608 | const invalid = new Date('Not a parsable date string'); 609 | 610 | is.date(invalid); 611 | //=> true 612 | invalid.getTime(); 613 | //=> NaN 614 | invalid.toUTCString(); 615 | //=> 'Invalid Date' 616 | is.validDate(invalid); 617 | //=> false 618 | ``` 619 | 620 | ##### .validLength(value) 621 | 622 | Returns `true` if the value is a safe integer that is greater than or equal to zero. 623 | 624 | This can be useful to confirm that a value is a valid count of something, ie. 0 or more. 625 | 626 | ##### .whitespaceString(value) 627 | 628 | Returns `true` if the value is a string with only whitespace characters. 629 | 630 | ## Type guards 631 | 632 | When using `is` together with TypeScript, [type guards](http://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types) are being used extensively to infer the correct type inside if-else statements. 633 | 634 | ```ts 635 | import is from '@sindresorhus/is'; 636 | 637 | const padLeft = (value: string, padding: string | number) => { 638 | if (is.number(padding)) { 639 | // `padding` is typed as `number` 640 | return Array(padding + 1).join(' ') + value; 641 | } 642 | 643 | if (is.string(padding)) { 644 | // `padding` is typed as `string` 645 | return padding + value; 646 | } 647 | 648 | throw new TypeError(`Expected 'padding' to be of type 'string' or 'number', got '${is(padding)}'.`); 649 | } 650 | 651 | padLeft('🦄', 3); 652 | //=> ' 🦄' 653 | 654 | padLeft('🦄', '🌈'); 655 | //=> '🌈🦄' 656 | ``` 657 | 658 | ## Type assertions 659 | 660 | The type guards are also available as [type assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions), which throw an error for unexpected types. It is a convenient one-line version of the often repetitive "if-not-expected-type-throw" pattern. 661 | 662 | ```ts 663 | import {assert} from '@sindresorhus/is'; 664 | 665 | const handleMovieRatingApiResponse = (response: unknown) => { 666 | assert.plainObject(response); 667 | // `response` is now typed as a plain `object` with `unknown` properties. 668 | 669 | assert.number(response.rating); 670 | // `response.rating` is now typed as a `number`. 671 | 672 | assert.string(response.title); 673 | // `response.title` is now typed as a `string`. 674 | 675 | return `${response.title} (${response.rating * 10})`; 676 | }; 677 | 678 | handleMovieRatingApiResponse({rating: 0.87, title: 'The Matrix'}); 679 | //=> 'The Matrix (8.7)' 680 | 681 | // This throws an error. 682 | handleMovieRatingApiResponse({rating: '🦄'}); 683 | ``` 684 | 685 | ## Generic type parameters 686 | 687 | The type guards and type assertions are aware of [generic type parameters](https://www.typescriptlang.org/docs/handbook/generics.html), such as `Promise` and `Map`. The default is `unknown` for most cases, since `is` cannot check them at runtime. If the generic type is known at compile-time, either implicitly (inferred) or explicitly (provided), `is` propagates the type so it can be used later. 688 | 689 | Use generic type parameters with caution. They are only checked by the TypeScript compiler, and not checked by `is` at runtime. This can lead to unexpected behavior, where the generic type is _assumed_ at compile-time, but actually is something completely different at runtime. It is best to use `unknown` (default) and type-check the value of the generic type parameter at runtime with `is` or `assert`. 690 | 691 | ```ts 692 | import {assert} from '@sindresorhus/is'; 693 | 694 | async function badNumberAssumption(input: unknown) { 695 | // Bad assumption about the generic type parameter fools the compile-time type system. 696 | assert.promise(input); 697 | // `input` is a `Promise` but only assumed to be `Promise`. 698 | 699 | const resolved = await input; 700 | // `resolved` is typed as `number` but was not actually checked at runtime. 701 | 702 | // Multiplication will return NaN if the input promise did not actually contain a number. 703 | return 2 * resolved; 704 | } 705 | 706 | async function goodNumberAssertion(input: unknown) { 707 | assert.promise(input); 708 | // `input` is typed as `Promise` 709 | 710 | const resolved = await input; 711 | // `resolved` is typed as `unknown` 712 | 713 | assert.number(resolved); 714 | // `resolved` is typed as `number` 715 | 716 | // Uses runtime checks so only numbers will reach the multiplication. 717 | return 2 * resolved; 718 | } 719 | 720 | badNumberAssumption(Promise.resolve('An unexpected string')); 721 | //=> NaN 722 | 723 | // This correctly throws an error because of the unexpected string value. 724 | goodNumberAssertion(Promise.resolve('An unexpected string')); 725 | ``` 726 | 727 | ## FAQ 728 | 729 | ### Why yet another type checking module? 730 | 731 | There are hundreds of type checking modules on npm, unfortunately, I couldn't find any that fit my needs: 732 | 733 | - Includes both type methods and ability to get the type 734 | - Types of primitives returned as lowercase and object types as camelcase 735 | - Covers all built-ins 736 | - Unsurprising behavior 737 | - Well-maintained 738 | - Comprehensive test suite 739 | 740 | For the ones I found, pick 3 of these. 741 | 742 | The most common mistakes I noticed in these modules was using `instanceof` for type checking, forgetting that functions are objects, and omitting `symbol` as a primitive. 743 | 744 | ### Why not just use `instanceof` instead of this package? 745 | 746 | `instanceof` does not work correctly for all types and it does not work across [realms](https://stackoverflow.com/a/49832343/64949). Examples of realms are iframes, windows, web workers, and the `vm` module in Node.js. 747 | 748 | ## Related 749 | 750 | - [environment](https://github.com/sindresorhus/environment) - Check which JavaScript environment your code is running in at runtime 751 | - [is-stream](https://github.com/sindresorhus/is-stream) - Check if something is a Node.js stream 752 | - [is-observable](https://github.com/sindresorhus/is-observable) - Check if a value is an Observable 753 | - [file-type](https://github.com/sindresorhus/file-type) - Detect the file type of a Buffer/Uint8Array 754 | - [is-ip](https://github.com/sindresorhus/is-ip) - Check if a string is an IP address 755 | - [is-array-sorted](https://github.com/sindresorhus/is-array-sorted) - Check if an Array is sorted 756 | - [is-error-constructor](https://github.com/sindresorhus/is-error-constructor) - Check if a value is an error constructor 757 | - [is-empty-iterable](https://github.com/sindresorhus/is-empty-iterable) - Check if an Iterable is empty 758 | - [is-blob](https://github.com/sindresorhus/is-blob) - Check if a value is a Blob - File-like object of immutable, raw data 759 | - [has-emoji](https://github.com/sindresorhus/has-emoji) - Check whether a string has any emoji 760 | 761 | ## Maintainers 762 | 763 | - [Sindre Sorhus](https://github.com/sindresorhus) 764 | - [Giora Guttsait](https://github.com/gioragutt) 765 | - [Brandon Smith](https://github.com/brandon93s) 766 | -------------------------------------------------------------------------------- /source/index.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ArrayLike, 3 | Class, 4 | Falsy, 5 | NodeStream, 6 | NonEmptyString, 7 | ObservableLike, 8 | Predicate, 9 | Primitive, 10 | TypedArray, 11 | WeakRef, 12 | Whitespace, 13 | } from './types.js'; 14 | 15 | // From type-fest. 16 | type ExtractFromGlobalConstructors = 17 | Name extends string 18 | ? typeof globalThis extends Record infer T> ? T : never 19 | : never; 20 | 21 | type NodeBuffer = ExtractFromGlobalConstructors<'Buffer'>; 22 | 23 | const typedArrayTypeNames = [ 24 | 'Int8Array', 25 | 'Uint8Array', 26 | 'Uint8ClampedArray', 27 | 'Int16Array', 28 | 'Uint16Array', 29 | 'Int32Array', 30 | 'Uint32Array', 31 | 'Float32Array', 32 | 'Float64Array', 33 | 'BigInt64Array', 34 | 'BigUint64Array', 35 | ] as const; 36 | 37 | type TypedArrayTypeName = typeof typedArrayTypeNames[number]; 38 | 39 | function isTypedArrayName(name: unknown): name is TypedArrayTypeName { 40 | return typedArrayTypeNames.includes(name as TypedArrayTypeName); 41 | } 42 | 43 | const objectTypeNames = [ 44 | 'Function', 45 | 'Generator', 46 | 'AsyncGenerator', 47 | 'GeneratorFunction', 48 | 'AsyncGeneratorFunction', 49 | 'AsyncFunction', 50 | 'Observable', 51 | 'Array', 52 | 'Buffer', 53 | 'Blob', 54 | 'Object', 55 | 'RegExp', 56 | 'Date', 57 | 'Error', 58 | 'Map', 59 | 'Set', 60 | 'WeakMap', 61 | 'WeakSet', 62 | 'WeakRef', 63 | 'ArrayBuffer', 64 | 'SharedArrayBuffer', 65 | 'DataView', 66 | 'Promise', 67 | 'URL', 68 | 'FormData', 69 | 'URLSearchParams', 70 | 'HTMLElement', 71 | 'NaN', 72 | ...typedArrayTypeNames, 73 | ] as const; 74 | 75 | type ObjectTypeName = typeof objectTypeNames[number]; 76 | 77 | function isObjectTypeName(name: unknown): name is ObjectTypeName { 78 | return objectTypeNames.includes(name as ObjectTypeName); 79 | } 80 | 81 | const primitiveTypeNames = [ 82 | 'null', 83 | 'undefined', 84 | 'string', 85 | 'number', 86 | 'bigint', 87 | 'boolean', 88 | 'symbol', 89 | ] as const; 90 | 91 | type PrimitiveTypeName = typeof primitiveTypeNames[number]; 92 | 93 | function isPrimitiveTypeName(name: unknown): name is PrimitiveTypeName { 94 | return primitiveTypeNames.includes(name as PrimitiveTypeName); 95 | } 96 | 97 | export type TypeName = ObjectTypeName | PrimitiveTypeName; 98 | 99 | const assertionTypeDescriptions = [ 100 | 'positive number', 101 | 'negative number', 102 | 'Class', 103 | 'string with a number', 104 | 'null or undefined', 105 | 'Iterable', 106 | 'AsyncIterable', 107 | 'native Promise', 108 | 'EnumCase', 109 | 'string with a URL', 110 | 'truthy', 111 | 'falsy', 112 | 'primitive', 113 | 'integer', 114 | 'plain object', 115 | 'TypedArray', 116 | 'array-like', 117 | 'tuple-like', 118 | 'Node.js Stream', 119 | 'infinite number', 120 | 'empty array', 121 | 'non-empty array', 122 | 'empty string', 123 | 'empty string or whitespace', 124 | 'non-empty string', 125 | 'non-empty string and not whitespace', 126 | 'empty object', 127 | 'non-empty object', 128 | 'empty set', 129 | 'non-empty set', 130 | 'empty map', 131 | 'non-empty map', 132 | 'PropertyKey', 133 | 'even integer', 134 | 'odd integer', 135 | 'T', 136 | 'in range', 137 | 'predicate returns truthy for any value', 138 | 'predicate returns truthy for all values', 139 | 'valid Date', 140 | 'valid length', 141 | 'whitespace string', 142 | ...objectTypeNames, 143 | ...primitiveTypeNames, 144 | ] as const; 145 | 146 | export type AssertionTypeDescription = typeof assertionTypeDescriptions[number]; 147 | 148 | const getObjectType = (value: unknown): ObjectTypeName | undefined => { 149 | const objectTypeName = Object.prototype.toString.call(value).slice(8, -1); 150 | 151 | if (/HTML\w+Element/.test(objectTypeName) && isHtmlElement(value)) { 152 | return 'HTMLElement'; 153 | } 154 | 155 | if (isObjectTypeName(objectTypeName)) { 156 | return objectTypeName; 157 | } 158 | 159 | return undefined; 160 | }; 161 | 162 | function detect(value: unknown): TypeName { 163 | if (value === null) { 164 | return 'null'; 165 | } 166 | 167 | switch (typeof value) { 168 | case 'undefined': { 169 | return 'undefined'; 170 | } 171 | 172 | case 'string': { 173 | return 'string'; 174 | } 175 | 176 | case 'number': { 177 | return Number.isNaN(value) ? 'NaN' : 'number'; 178 | } 179 | 180 | case 'boolean': { 181 | return 'boolean'; 182 | } 183 | 184 | case 'function': { 185 | return 'Function'; 186 | } 187 | 188 | case 'bigint': { 189 | return 'bigint'; 190 | } 191 | 192 | case 'symbol': { 193 | return 'symbol'; 194 | } 195 | 196 | default: 197 | } 198 | 199 | if (isObservable(value)) { 200 | return 'Observable'; 201 | } 202 | 203 | if (isArray(value)) { 204 | return 'Array'; 205 | } 206 | 207 | if (isBuffer(value)) { 208 | return 'Buffer'; 209 | } 210 | 211 | const tagType = getObjectType(value); 212 | if (tagType) { 213 | return tagType; 214 | } 215 | 216 | if (value instanceof String || value instanceof Boolean || value instanceof Number) { 217 | throw new TypeError('Please don\'t use object wrappers for primitive types'); 218 | } 219 | 220 | return 'Object'; 221 | } 222 | 223 | function hasPromiseApi(value: unknown): value is Promise { 224 | return isFunction((value as Promise)?.then) && isFunction((value as Promise)?.catch); 225 | } 226 | 227 | const is = Object.assign( 228 | detect, 229 | { 230 | all: isAll, 231 | any: isAny, 232 | array: isArray, 233 | arrayBuffer: isArrayBuffer, 234 | arrayLike: isArrayLike, 235 | asyncFunction: isAsyncFunction, 236 | asyncGenerator: isAsyncGenerator, 237 | asyncGeneratorFunction: isAsyncGeneratorFunction, 238 | asyncIterable: isAsyncIterable, 239 | bigint: isBigint, 240 | bigInt64Array: isBigInt64Array, 241 | bigUint64Array: isBigUint64Array, 242 | blob: isBlob, 243 | boolean: isBoolean, 244 | boundFunction: isBoundFunction, 245 | buffer: isBuffer, 246 | class: isClass, 247 | dataView: isDataView, 248 | date: isDate, 249 | detect, 250 | directInstanceOf: isDirectInstanceOf, 251 | emptyArray: isEmptyArray, 252 | emptyMap: isEmptyMap, 253 | emptyObject: isEmptyObject, 254 | emptySet: isEmptySet, 255 | emptyString: isEmptyString, 256 | emptyStringOrWhitespace: isEmptyStringOrWhitespace, 257 | enumCase: isEnumCase, 258 | error: isError, 259 | evenInteger: isEvenInteger, 260 | falsy: isFalsy, 261 | float32Array: isFloat32Array, 262 | float64Array: isFloat64Array, 263 | formData: isFormData, 264 | function: isFunction, 265 | generator: isGenerator, 266 | generatorFunction: isGeneratorFunction, 267 | htmlElement: isHtmlElement, 268 | infinite: isInfinite, 269 | inRange: isInRange, 270 | int16Array: isInt16Array, 271 | int32Array: isInt32Array, 272 | int8Array: isInt8Array, 273 | integer: isInteger, 274 | iterable: isIterable, 275 | map: isMap, 276 | nan: isNan, 277 | nativePromise: isNativePromise, 278 | negativeNumber: isNegativeNumber, 279 | nodeStream: isNodeStream, 280 | nonEmptyArray: isNonEmptyArray, 281 | nonEmptyMap: isNonEmptyMap, 282 | nonEmptyObject: isNonEmptyObject, 283 | nonEmptySet: isNonEmptySet, 284 | nonEmptyString: isNonEmptyString, 285 | nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace, 286 | null: isNull, 287 | nullOrUndefined: isNullOrUndefined, 288 | number: isNumber, 289 | numericString: isNumericString, 290 | object: isObject, 291 | observable: isObservable, 292 | oddInteger: isOddInteger, 293 | plainObject: isPlainObject, 294 | positiveNumber: isPositiveNumber, 295 | primitive: isPrimitive, 296 | promise: isPromise, 297 | propertyKey: isPropertyKey, 298 | regExp: isRegExp, 299 | safeInteger: isSafeInteger, 300 | set: isSet, 301 | sharedArrayBuffer: isSharedArrayBuffer, 302 | string: isString, 303 | symbol: isSymbol, 304 | truthy: isTruthy, 305 | tupleLike: isTupleLike, 306 | typedArray: isTypedArray, 307 | uint16Array: isUint16Array, 308 | uint32Array: isUint32Array, 309 | uint8Array: isUint8Array, 310 | uint8ClampedArray: isUint8ClampedArray, 311 | undefined: isUndefined, 312 | urlInstance: isUrlInstance, 313 | urlSearchParams: isUrlSearchParams, 314 | urlString: isUrlString, 315 | validDate: isValidDate, 316 | validLength: isValidLength, 317 | weakMap: isWeakMap, 318 | weakRef: isWeakRef, 319 | weakSet: isWeakSet, 320 | whitespaceString: isWhitespaceString, 321 | }, 322 | ); 323 | 324 | function isAbsoluteModule2(remainder: 0 | 1) { 325 | return (value: unknown): value is number => isInteger(value) && Math.abs(value % 2) === remainder; 326 | } 327 | 328 | export function isAll(predicate: Predicate, ...values: unknown[]): boolean { 329 | return predicateOnArray(Array.prototype.every, predicate, values); 330 | } 331 | 332 | export function isAny(predicate: Predicate | Predicate[], ...values: unknown[]): boolean { 333 | const predicates = isArray(predicate) ? predicate : [predicate]; 334 | return predicates.some(singlePredicate => 335 | predicateOnArray(Array.prototype.some, singlePredicate, values), 336 | ); 337 | } 338 | 339 | export function isArray(value: unknown, assertion?: (value: T) => value is T): value is T[] { 340 | if (!Array.isArray(value)) { 341 | return false; 342 | } 343 | 344 | if (!isFunction(assertion)) { 345 | return true; 346 | } 347 | 348 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 349 | return value.every(element => assertion(element)); 350 | } 351 | 352 | export function isArrayBuffer(value: unknown): value is ArrayBuffer { 353 | return getObjectType(value) === 'ArrayBuffer'; 354 | } 355 | 356 | export function isArrayLike(value: unknown): value is ArrayLike { 357 | return !isNullOrUndefined(value) && !isFunction(value) && isValidLength((value as ArrayLike).length); 358 | } 359 | 360 | export function isAsyncFunction(value: unknown): value is ((...arguments_: any[]) => Promise) { 361 | return getObjectType(value) === 'AsyncFunction'; 362 | } 363 | 364 | export function isAsyncGenerator(value: unknown): value is AsyncGenerator { 365 | return isAsyncIterable(value) && isFunction((value as AsyncGenerator).next) && isFunction((value as AsyncGenerator).throw); 366 | } 367 | 368 | export function isAsyncGeneratorFunction(value: unknown): value is ((...arguments_: any[]) => Promise) { 369 | return getObjectType(value) === 'AsyncGeneratorFunction'; 370 | } 371 | 372 | export function isAsyncIterable(value: unknown): value is AsyncIterable { 373 | return isFunction((value as AsyncIterable)?.[Symbol.asyncIterator]); 374 | } 375 | 376 | export function isBigint(value: unknown): value is bigint { 377 | return typeof value === 'bigint'; 378 | } 379 | 380 | export function isBigInt64Array(value: unknown): value is BigInt64Array { 381 | return getObjectType(value) === 'BigInt64Array'; 382 | } 383 | 384 | export function isBigUint64Array(value: unknown): value is BigUint64Array { 385 | return getObjectType(value) === 'BigUint64Array'; 386 | } 387 | 388 | export function isBlob(value: unknown): value is Blob { 389 | return getObjectType(value) === 'Blob'; 390 | } 391 | 392 | export function isBoolean(value: unknown): value is boolean { 393 | return value === true || value === false; 394 | } 395 | 396 | // eslint-disable-next-line @typescript-eslint/ban-types 397 | export function isBoundFunction(value: unknown): value is Function { 398 | return isFunction(value) && !Object.hasOwn(value, 'prototype'); 399 | } 400 | 401 | /** 402 | Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) 403 | */ 404 | export function isBuffer(value: unknown): value is NodeBuffer { 405 | // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call 406 | return (value as any)?.constructor?.isBuffer?.(value) ?? false; 407 | } 408 | 409 | export function isClass(value: unknown): value is Class { 410 | return isFunction(value) && value.toString().startsWith('class '); 411 | } 412 | 413 | export function isDataView(value: unknown): value is DataView { 414 | return getObjectType(value) === 'DataView'; 415 | } 416 | 417 | export function isDate(value: unknown): value is Date { 418 | return getObjectType(value) === 'Date'; 419 | } 420 | 421 | export function isDirectInstanceOf(instance: unknown, class_: Class): instance is T { 422 | if (instance === undefined || instance === null) { 423 | return false; 424 | } 425 | 426 | return Object.getPrototypeOf(instance) === class_.prototype; 427 | } 428 | 429 | export function isEmptyArray(value: unknown): value is never[] { 430 | return isArray(value) && value.length === 0; 431 | } 432 | 433 | export function isEmptyMap(value: unknown): value is Map { 434 | return isMap(value) && value.size === 0; 435 | } 436 | 437 | export function isEmptyObject(value: unknown): value is Record { 438 | return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0; 439 | } 440 | 441 | export function isEmptySet(value: unknown): value is Set { 442 | return isSet(value) && value.size === 0; 443 | } 444 | 445 | export function isEmptyString(value: unknown): value is '' { 446 | return isString(value) && value.length === 0; 447 | } 448 | 449 | export function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitespace { 450 | return isEmptyString(value) || isWhitespaceString(value); 451 | } 452 | 453 | export function isEnumCase(value: unknown, targetEnum: T): value is T[keyof T] { 454 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 455 | return Object.values(targetEnum as any).includes(value as string); 456 | } 457 | 458 | export function isError(value: unknown): value is Error { 459 | return getObjectType(value) === 'Error'; 460 | } 461 | 462 | export function isEvenInteger(value: unknown): value is number { 463 | return isAbsoluteModule2(0)(value); 464 | } 465 | 466 | // Example: `is.falsy = (value: unknown): value is (not true | 0 | '' | undefined | null) => Boolean(value);` 467 | export function isFalsy(value: unknown): value is Falsy { 468 | return !value; 469 | } 470 | 471 | export function isFloat32Array(value: unknown): value is Float32Array { 472 | return getObjectType(value) === 'Float32Array'; 473 | } 474 | 475 | export function isFloat64Array(value: unknown): value is Float64Array { 476 | return getObjectType(value) === 'Float64Array'; 477 | } 478 | 479 | export function isFormData(value: unknown): value is FormData { 480 | return getObjectType(value) === 'FormData'; 481 | } 482 | 483 | // eslint-disable-next-line @typescript-eslint/ban-types 484 | export function isFunction(value: unknown): value is Function { 485 | return typeof value === 'function'; 486 | } 487 | 488 | export function isGenerator(value: unknown): value is Generator { 489 | return isIterable(value) && isFunction((value as Generator)?.next) && isFunction((value as Generator)?.throw); 490 | } 491 | 492 | export function isGeneratorFunction(value: unknown): value is GeneratorFunction { 493 | return getObjectType(value) === 'GeneratorFunction'; 494 | } 495 | 496 | // eslint-disable-next-line @typescript-eslint/naming-convention 497 | const NODE_TYPE_ELEMENT = 1; 498 | 499 | // eslint-disable-next-line @typescript-eslint/naming-convention 500 | const DOM_PROPERTIES_TO_CHECK: Array<(keyof HTMLElement)> = [ 501 | 'innerHTML', 502 | 'ownerDocument', 503 | 'style', 504 | 'attributes', 505 | 'nodeValue', 506 | ]; 507 | 508 | export function isHtmlElement(value: unknown): value is HTMLElement { 509 | return isObject(value) 510 | && (value as HTMLElement).nodeType === NODE_TYPE_ELEMENT 511 | && isString((value as HTMLElement).nodeName) 512 | && !isPlainObject(value) 513 | && DOM_PROPERTIES_TO_CHECK.every(property => property in value); 514 | } 515 | 516 | export function isInfinite(value: unknown): value is number { 517 | return value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY; 518 | } 519 | 520 | export function isInRange(value: number, range: number | [number, number]): value is number { 521 | if (isNumber(range)) { 522 | return value >= Math.min(0, range) && value <= Math.max(range, 0); 523 | } 524 | 525 | if (isArray(range) && range.length === 2) { 526 | return value >= Math.min(...range) && value <= Math.max(...range); 527 | } 528 | 529 | throw new TypeError(`Invalid range: ${JSON.stringify(range)}`); 530 | } 531 | 532 | export function isInt16Array(value: unknown): value is Int16Array { 533 | return getObjectType(value) === 'Int16Array'; 534 | } 535 | 536 | export function isInt32Array(value: unknown): value is Int32Array { 537 | return getObjectType(value) === 'Int32Array'; 538 | } 539 | 540 | export function isInt8Array(value: unknown): value is Int8Array { 541 | return getObjectType(value) === 'Int8Array'; 542 | } 543 | 544 | export function isInteger(value: unknown): value is number { 545 | return Number.isInteger(value); 546 | } 547 | 548 | export function isIterable(value: unknown): value is Iterable { 549 | return isFunction((value as Iterable)?.[Symbol.iterator]); 550 | } 551 | 552 | export function isMap(value: unknown): value is Map { 553 | return getObjectType(value) === 'Map'; 554 | } 555 | 556 | export function isNan(value: unknown) { 557 | return Number.isNaN(value); 558 | } 559 | 560 | export function isNativePromise(value: unknown): value is Promise { 561 | return getObjectType(value) === 'Promise'; 562 | } 563 | 564 | export function isNegativeNumber(value: unknown): value is number { 565 | return isNumber(value) && value < 0; 566 | } 567 | 568 | export function isNodeStream(value: unknown): value is NodeStream { 569 | return isObject(value) && isFunction((value as NodeStream).pipe) && !isObservable(value); 570 | } 571 | 572 | export function isNonEmptyArray(value: T | Item[]): value is [Item, ...Item[]] { 573 | return isArray(value) && value.length > 0; 574 | } 575 | 576 | export function isNonEmptyMap(value: unknown): value is Map { 577 | return isMap(value) && value.size > 0; 578 | } 579 | 580 | // TODO: Use `not` operator here to remove `Map` and `Set` from type guard: 581 | // - https://github.com/Microsoft/TypeScript/pull/29317 582 | export function isNonEmptyObject(value: unknown): value is Record { 583 | return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0; 584 | } 585 | 586 | export function isNonEmptySet(value: unknown): value is Set { 587 | return isSet(value) && value.size > 0; 588 | } 589 | 590 | // TODO: Use `not ''` when the `not` operator is available. 591 | export function isNonEmptyString(value: unknown): value is NonEmptyString { 592 | return isString(value) && value.length > 0; 593 | } 594 | 595 | // TODO: Use `not ''` when the `not` operator is available. 596 | export function isNonEmptyStringAndNotWhitespace(value: unknown): value is NonEmptyString { 597 | return isString(value) && !isEmptyStringOrWhitespace(value); 598 | } 599 | 600 | // eslint-disable-next-line @typescript-eslint/ban-types 601 | export function isNull(value: unknown): value is null { 602 | return value === null; 603 | } 604 | 605 | // eslint-disable-next-line @typescript-eslint/ban-types 606 | export function isNullOrUndefined(value: unknown): value is null | undefined { 607 | return isNull(value) || isUndefined(value); 608 | } 609 | 610 | export function isNumber(value: unknown): value is number { 611 | return typeof value === 'number' && !Number.isNaN(value); 612 | } 613 | 614 | export function isNumericString(value: unknown): value is `${number}` { 615 | return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value)); 616 | } 617 | 618 | // eslint-disable-next-line @typescript-eslint/ban-types 619 | export function isObject(value: unknown): value is object { 620 | return !isNull(value) && (typeof value === 'object' || isFunction(value)); 621 | } 622 | 623 | export function isObservable(value: unknown): value is ObservableLike { 624 | if (!value) { 625 | return false; 626 | } 627 | 628 | // eslint-disable-next-line no-use-extend-native/no-use-extend-native, @typescript-eslint/no-unsafe-call 629 | if (value === (value as any)[Symbol.observable]?.()) { 630 | return true; 631 | } 632 | 633 | // eslint-disable-next-line @typescript-eslint/no-unsafe-call 634 | if (value === (value as any)['@@observable']?.()) { 635 | return true; 636 | } 637 | 638 | return false; 639 | } 640 | 641 | export function isOddInteger(value: unknown): value is number { 642 | return isAbsoluteModule2(1)(value); 643 | } 644 | 645 | export function isPlainObject(value: unknown): value is Record { 646 | // From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js 647 | if (typeof value !== 'object' || value === null) { 648 | return false; 649 | } 650 | 651 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 652 | const prototype = Object.getPrototypeOf(value); 653 | 654 | return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value); 655 | } 656 | 657 | export function isPositiveNumber(value: unknown): value is number { 658 | return isNumber(value) && value > 0; 659 | } 660 | 661 | export function isPrimitive(value: unknown): value is Primitive { 662 | return isNull(value) || isPrimitiveTypeName(typeof value); 663 | } 664 | 665 | export function isPromise(value: unknown): value is Promise { 666 | return isNativePromise(value) || hasPromiseApi(value); 667 | } 668 | 669 | // `PropertyKey` is any value that can be used as an object key (string, number, or symbol) 670 | export function isPropertyKey(value: unknown): value is PropertyKey { 671 | return isAny([isString, isNumber, isSymbol], value); 672 | } 673 | 674 | export function isRegExp(value: unknown): value is RegExp { 675 | return getObjectType(value) === 'RegExp'; 676 | } 677 | 678 | export function isSafeInteger(value: unknown): value is number { 679 | return Number.isSafeInteger(value); 680 | } 681 | 682 | export function isSet(value: unknown): value is Set { 683 | return getObjectType(value) === 'Set'; 684 | } 685 | 686 | export function isSharedArrayBuffer(value: unknown): value is SharedArrayBuffer { 687 | return getObjectType(value) === 'SharedArrayBuffer'; 688 | } 689 | 690 | export function isString(value: unknown): value is string { 691 | return typeof value === 'string'; 692 | } 693 | 694 | export function isSymbol(value: unknown): value is symbol { 695 | return typeof value === 'symbol'; 696 | } 697 | 698 | // Example: `is.truthy = (value: unknown): value is (not false | not 0 | not '' | not undefined | not null) => Boolean(value);` 699 | // eslint-disable-next-line unicorn/prefer-native-coercion-functions 700 | export function isTruthy(value: T | Falsy): value is T { 701 | return Boolean(value); 702 | } 703 | 704 | type TypeGuard = (value: unknown) => value is T; 705 | 706 | // eslint-disable-next-line @typescript-eslint/ban-types 707 | type ResolveTypesOfTypeGuardsTuple = 708 | TypeGuardsOfT extends [TypeGuard, ...infer TOthers] 709 | ? ResolveTypesOfTypeGuardsTuple 710 | : TypeGuardsOfT extends undefined[] 711 | ? ResultOfT 712 | : never; 713 | 714 | export function isTupleLike>>(value: unknown, guards: [...T]): value is ResolveTypesOfTypeGuardsTuple { 715 | if (isArray(guards) && isArray(value) && guards.length === value.length) { 716 | return guards.every((guard, index) => guard(value[index])); 717 | } 718 | 719 | return false; 720 | } 721 | 722 | export function isTypedArray(value: unknown): value is TypedArray { 723 | return isTypedArrayName(getObjectType(value)); 724 | } 725 | 726 | export function isUint16Array(value: unknown): value is Uint16Array { 727 | return getObjectType(value) === 'Uint16Array'; 728 | } 729 | 730 | export function isUint32Array(value: unknown): value is Uint32Array { 731 | return getObjectType(value) === 'Uint32Array'; 732 | } 733 | 734 | export function isUint8Array(value: unknown): value is Uint8Array { 735 | return getObjectType(value) === 'Uint8Array'; 736 | } 737 | 738 | export function isUint8ClampedArray(value: unknown): value is Uint8ClampedArray { 739 | return getObjectType(value) === 'Uint8ClampedArray'; 740 | } 741 | 742 | export function isUndefined(value: unknown): value is undefined { 743 | return value === undefined; 744 | } 745 | 746 | export function isUrlInstance(value: unknown): value is URL { 747 | return getObjectType(value) === 'URL'; 748 | } 749 | 750 | // eslint-disable-next-line unicorn/prevent-abbreviations 751 | export function isUrlSearchParams(value: unknown): value is URLSearchParams { 752 | return getObjectType(value) === 'URLSearchParams'; 753 | } 754 | 755 | export function isUrlString(value: unknown): value is string { 756 | if (!isString(value)) { 757 | return false; 758 | } 759 | 760 | try { 761 | new URL(value); // eslint-disable-line no-new 762 | return true; 763 | } catch { 764 | return false; 765 | } 766 | } 767 | 768 | export function isValidDate(value: unknown): value is Date { 769 | return isDate(value) && !isNan(Number(value)); 770 | } 771 | 772 | export function isValidLength(value: unknown): value is number { 773 | return isSafeInteger(value) && value >= 0; 774 | } 775 | 776 | // eslint-disable-next-line @typescript-eslint/ban-types 777 | export function isWeakMap(value: unknown): value is WeakMap { 778 | return getObjectType(value) === 'WeakMap'; 779 | } 780 | 781 | // eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations 782 | export function isWeakRef(value: unknown): value is WeakRef { 783 | return getObjectType(value) === 'WeakRef'; 784 | } 785 | 786 | // eslint-disable-next-line @typescript-eslint/ban-types 787 | export function isWeakSet(value: unknown): value is WeakSet { 788 | return getObjectType(value) === 'WeakSet'; 789 | } 790 | 791 | export function isWhitespaceString(value: unknown): value is Whitespace { 792 | return isString(value) && /^\s+$/.test(value); 793 | } 794 | 795 | type ArrayMethod = (function_: (value: unknown, index: number, array: unknown[]) => boolean, thisArgument?: unknown) => boolean; 796 | 797 | function predicateOnArray(method: ArrayMethod, predicate: Predicate, values: unknown[]) { 798 | if (!isFunction(predicate)) { 799 | throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); 800 | } 801 | 802 | if (values.length === 0) { 803 | throw new TypeError('Invalid number of values'); 804 | } 805 | 806 | return method.call(values, predicate); 807 | } 808 | 809 | function typeErrorMessage(description: AssertionTypeDescription, value: unknown): string { 810 | return `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`; 811 | } 812 | 813 | function unique(values: T[]): T[] { 814 | // eslint-disable-next-line unicorn/prefer-spread 815 | return Array.from(new Set(values)); 816 | } 817 | 818 | const andFormatter = new Intl.ListFormat('en', {style: 'long', type: 'conjunction'}); 819 | const orFormatter = new Intl.ListFormat('en', {style: 'long', type: 'disjunction'}); 820 | 821 | function typeErrorMessageMultipleValues(expectedType: AssertionTypeDescription | AssertionTypeDescription[], values: unknown[]): string { 822 | const uniqueExpectedTypes = unique((isArray(expectedType) ? expectedType : [expectedType]).map(value => `\`${value}\``)); 823 | const uniqueValueTypes = unique(values.map(value => `\`${is(value)}\``)); 824 | return `Expected values which are ${orFormatter.format(uniqueExpectedTypes)}. Received values of type${uniqueValueTypes.length > 1 ? 's' : ''} ${andFormatter.format(uniqueValueTypes)}.`; 825 | } 826 | 827 | // Type assertions have to be declared with an explicit type. 828 | type Assert = { 829 | // Unknowns. 830 | undefined: (value: unknown, message?: string) => asserts value is undefined; 831 | string: (value: unknown, message?: string) => asserts value is string; 832 | number: (value: unknown, message?: string) => asserts value is number; 833 | positiveNumber: (value: unknown, message?: string) => asserts value is number; 834 | negativeNumber: (value: unknown, message?: string) => asserts value is number; 835 | bigint: (value: unknown, message?: string) => asserts value is bigint; 836 | // eslint-disable-next-line @typescript-eslint/ban-types 837 | function: (value: unknown, message?: string) => asserts value is Function; 838 | // eslint-disable-next-line @typescript-eslint/ban-types 839 | null: (value: unknown, message?: string) => asserts value is null; 840 | class: (value: unknown, message?: string) => asserts value is Class; 841 | boolean: (value: unknown, message?: string) => asserts value is boolean; 842 | symbol: (value: unknown, message?: string) => asserts value is symbol; 843 | numericString: (value: unknown, message?: string) => asserts value is `${number}`; 844 | array: (value: unknown, assertion?: (element: unknown) => asserts element is T, message?: string) => asserts value is T[]; 845 | buffer: (value: unknown, message?: string) => asserts value is NodeBuffer; 846 | blob: (value: unknown, message?: string) => asserts value is Blob; 847 | // eslint-disable-next-line @typescript-eslint/ban-types 848 | nullOrUndefined: (value: unknown, message?: string) => asserts value is null | undefined; 849 | object: (value: unknown, message?: string) => asserts value is Record; 850 | iterable: (value: unknown, message?: string) => asserts value is Iterable; 851 | asyncIterable: (value: unknown, message?: string) => asserts value is AsyncIterable; 852 | generator: (value: unknown, message?: string) => asserts value is Generator; 853 | asyncGenerator: (value: unknown, message?: string) => asserts value is AsyncGenerator; 854 | nativePromise: (value: unknown, message?: string) => asserts value is Promise; 855 | promise: (value: unknown, message?: string) => asserts value is Promise; 856 | generatorFunction: (value: unknown, message?: string) => asserts value is GeneratorFunction; 857 | asyncGeneratorFunction: (value: unknown, message?: string) => asserts value is AsyncGeneratorFunction; 858 | // eslint-disable-next-line @typescript-eslint/ban-types 859 | asyncFunction: (value: unknown, message?: string) => asserts value is Function; 860 | // eslint-disable-next-line @typescript-eslint/ban-types 861 | boundFunction: (value: unknown, message?: string) => asserts value is Function; 862 | regExp: (value: unknown, message?: string) => asserts value is RegExp; 863 | date: (value: unknown, message?: string) => asserts value is Date; 864 | error: (value: unknown, message?: string) => asserts value is Error; 865 | map: (value: unknown, message?: string) => asserts value is Map; 866 | set: (value: unknown, message?: string) => asserts value is Set; 867 | // eslint-disable-next-line @typescript-eslint/ban-types 868 | weakMap: (value: unknown, message?: string) => asserts value is WeakMap; 869 | // eslint-disable-next-line @typescript-eslint/ban-types 870 | weakSet: (value: unknown, message?: string) => asserts value is WeakSet; 871 | // eslint-disable-next-line @typescript-eslint/ban-types 872 | weakRef: (value: unknown, message?: string) => asserts value is WeakRef; 873 | int8Array: (value: unknown, message?: string) => asserts value is Int8Array; 874 | uint8Array: (value: unknown, message?: string) => asserts value is Uint8Array; 875 | uint8ClampedArray: (value: unknown, message?: string) => asserts value is Uint8ClampedArray; 876 | int16Array: (value: unknown, message?: string) => asserts value is Int16Array; 877 | uint16Array: (value: unknown, message?: string) => asserts value is Uint16Array; 878 | int32Array: (value: unknown, message?: string) => asserts value is Int32Array; 879 | uint32Array: (value: unknown, message?: string) => asserts value is Uint32Array; 880 | float32Array: (value: unknown, message?: string) => asserts value is Float32Array; 881 | float64Array: (value: unknown, message?: string) => asserts value is Float64Array; 882 | bigInt64Array: (value: unknown, message?: string) => asserts value is BigInt64Array; 883 | bigUint64Array: (value: unknown, message?: string) => asserts value is BigUint64Array; 884 | arrayBuffer: (value: unknown, message?: string) => asserts value is ArrayBuffer; 885 | sharedArrayBuffer: (value: unknown, message?: string) => asserts value is SharedArrayBuffer; 886 | dataView: (value: unknown, message?: string) => asserts value is DataView; 887 | enumCase: (value: unknown, targetEnum: T, message?: string) => asserts value is T[keyof T]; 888 | urlInstance: (value: unknown, message?: string) => asserts value is URL; 889 | urlString: (value: unknown, message?: string) => asserts value is string; 890 | truthy: (value: T | Falsy, message?: string) => asserts value is T; 891 | falsy: (value: unknown, message?: string) => asserts value is Falsy; 892 | nan: (value: unknown, message?: string) => asserts value is number; 893 | primitive: (value: unknown, message?: string) => asserts value is Primitive; 894 | integer: (value: unknown, message?: string) => asserts value is number; 895 | safeInteger: (value: unknown, message?: string) => asserts value is number; 896 | plainObject: (value: unknown, message?: string) => asserts value is Record; 897 | typedArray: (value: unknown, message?: string) => asserts value is TypedArray; 898 | arrayLike: (value: unknown, message?: string) => asserts value is ArrayLike; 899 | tupleLike: >>(value: unknown, guards: [...T], message?: string) => asserts value is ResolveTypesOfTypeGuardsTuple; 900 | htmlElement: (value: unknown, message?: string) => asserts value is HTMLElement; 901 | observable: (value: unknown, message?: string) => asserts value is ObservableLike; 902 | nodeStream: (value: unknown, message?: string) => asserts value is NodeStream; 903 | infinite: (value: unknown, message?: string) => asserts value is number; 904 | emptyArray: (value: unknown, message?: string) => asserts value is never[]; 905 | nonEmptyArray: (value: T | Item[], message?: string) => asserts value is [Item, ...Item[]]; 906 | emptyString: (value: unknown, message?: string) => asserts value is ''; 907 | emptyStringOrWhitespace: (value: unknown, message?: string) => asserts value is '' | Whitespace; 908 | nonEmptyString: (value: unknown, message?: string) => asserts value is string; 909 | nonEmptyStringAndNotWhitespace: (value: unknown, message?: string) => asserts value is string; 910 | emptyObject: (value: unknown, message?: string) => asserts value is Record; 911 | nonEmptyObject: (value: unknown, message?: string) => asserts value is Record; 912 | emptySet: (value: unknown, message?: string) => asserts value is Set; 913 | nonEmptySet: (value: unknown, message?: string) => asserts value is Set; 914 | emptyMap: (value: unknown, message?: string) => asserts value is Map; 915 | nonEmptyMap: (value: unknown, message?: string) => asserts value is Map; 916 | propertyKey: (value: unknown, message?: string) => asserts value is PropertyKey; 917 | formData: (value: unknown, message?: string) => asserts value is FormData; 918 | urlSearchParams: (value: unknown, message?: string) => asserts value is URLSearchParams; 919 | validDate: (value: unknown, message?: string) => asserts value is Date; 920 | validLength: (value: unknown, message?: string) => asserts value is number; 921 | whitespaceString: (value: unknown, message?: string) => asserts value is string; 922 | 923 | // Numbers. 924 | evenInteger: (value: number, message?: string) => asserts value is number; 925 | oddInteger: (value: number, message?: string) => asserts value is number; 926 | 927 | // Two arguments. 928 | directInstanceOf: (instance: unknown, class_: Class, message?: string) => asserts instance is T; 929 | inRange: (value: number, range: number | [number, number], message?: string) => asserts value is number; 930 | 931 | // Variadic functions. 932 | any: (predicate: Predicate | Predicate[], ...values: unknown[]) => void | never; 933 | all: (predicate: Predicate, ...values: unknown[]) => void | never; 934 | }; 935 | 936 | export const assert: Assert = { 937 | all: assertAll, 938 | any: assertAny, 939 | array: assertArray, 940 | arrayBuffer: assertArrayBuffer, 941 | arrayLike: assertArrayLike, 942 | asyncFunction: assertAsyncFunction, 943 | asyncGenerator: assertAsyncGenerator, 944 | asyncGeneratorFunction: assertAsyncGeneratorFunction, 945 | asyncIterable: assertAsyncIterable, 946 | bigint: assertBigint, 947 | bigInt64Array: assertBigInt64Array, 948 | bigUint64Array: assertBigUint64Array, 949 | blob: assertBlob, 950 | boolean: assertBoolean, 951 | boundFunction: assertBoundFunction, 952 | buffer: assertBuffer, 953 | class: assertClass, 954 | dataView: assertDataView, 955 | date: assertDate, 956 | directInstanceOf: assertDirectInstanceOf, 957 | emptyArray: assertEmptyArray, 958 | emptyMap: assertEmptyMap, 959 | emptyObject: assertEmptyObject, 960 | emptySet: assertEmptySet, 961 | emptyString: assertEmptyString, 962 | emptyStringOrWhitespace: assertEmptyStringOrWhitespace, 963 | enumCase: assertEnumCase, 964 | error: assertError, 965 | evenInteger: assertEvenInteger, 966 | falsy: assertFalsy, 967 | float32Array: assertFloat32Array, 968 | float64Array: assertFloat64Array, 969 | formData: assertFormData, 970 | function: assertFunction, 971 | generator: assertGenerator, 972 | generatorFunction: assertGeneratorFunction, 973 | htmlElement: assertHtmlElement, 974 | infinite: assertInfinite, 975 | inRange: assertInRange, 976 | int16Array: assertInt16Array, 977 | int32Array: assertInt32Array, 978 | int8Array: assertInt8Array, 979 | integer: assertInteger, 980 | iterable: assertIterable, 981 | map: assertMap, 982 | nan: assertNan, 983 | nativePromise: assertNativePromise, 984 | negativeNumber: assertNegativeNumber, 985 | nodeStream: assertNodeStream, 986 | nonEmptyArray: assertNonEmptyArray, 987 | nonEmptyMap: assertNonEmptyMap, 988 | nonEmptyObject: assertNonEmptyObject, 989 | nonEmptySet: assertNonEmptySet, 990 | nonEmptyString: assertNonEmptyString, 991 | nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace, 992 | null: assertNull, 993 | nullOrUndefined: assertNullOrUndefined, 994 | number: assertNumber, 995 | numericString: assertNumericString, 996 | object: assertObject, 997 | observable: assertObservable, 998 | oddInteger: assertOddInteger, 999 | plainObject: assertPlainObject, 1000 | positiveNumber: assertPositiveNumber, 1001 | primitive: assertPrimitive, 1002 | promise: assertPromise, 1003 | propertyKey: assertPropertyKey, 1004 | regExp: assertRegExp, 1005 | safeInteger: assertSafeInteger, 1006 | set: assertSet, 1007 | sharedArrayBuffer: assertSharedArrayBuffer, 1008 | string: assertString, 1009 | symbol: assertSymbol, 1010 | truthy: assertTruthy, 1011 | tupleLike: assertTupleLike, 1012 | typedArray: assertTypedArray, 1013 | uint16Array: assertUint16Array, 1014 | uint32Array: assertUint32Array, 1015 | uint8Array: assertUint8Array, 1016 | uint8ClampedArray: assertUint8ClampedArray, 1017 | undefined: assertUndefined, 1018 | urlInstance: assertUrlInstance, 1019 | urlSearchParams: assertUrlSearchParams, 1020 | urlString: assertUrlString, 1021 | validDate: assertValidDate, 1022 | validLength: assertValidLength, 1023 | weakMap: assertWeakMap, 1024 | weakRef: assertWeakRef, 1025 | weakSet: assertWeakSet, 1026 | whitespaceString: assertWhitespaceString, 1027 | }; 1028 | 1029 | const methodTypeMap = { 1030 | isArray: 'Array', 1031 | isArrayBuffer: 'ArrayBuffer', 1032 | isArrayLike: 'array-like', 1033 | isAsyncFunction: 'AsyncFunction', 1034 | isAsyncGenerator: 'AsyncGenerator', 1035 | isAsyncGeneratorFunction: 'AsyncGeneratorFunction', 1036 | isAsyncIterable: 'AsyncIterable', 1037 | isBigint: 'bigint', 1038 | isBigInt64Array: 'BigInt64Array', 1039 | isBigUint64Array: 'BigUint64Array', 1040 | isBlob: 'Blob', 1041 | isBoolean: 'boolean', 1042 | isBoundFunction: 'Function', 1043 | isBuffer: 'Buffer', 1044 | isClass: 'Class', 1045 | isDataView: 'DataView', 1046 | isDate: 'Date', 1047 | isDirectInstanceOf: 'T', 1048 | isEmptyArray: 'empty array', 1049 | isEmptyMap: 'empty map', 1050 | isEmptyObject: 'empty object', 1051 | isEmptySet: 'empty set', 1052 | isEmptyString: 'empty string', 1053 | isEmptyStringOrWhitespace: 'empty string or whitespace', 1054 | isEnumCase: 'EnumCase', 1055 | isError: 'Error', 1056 | isEvenInteger: 'even integer', 1057 | isFalsy: 'falsy', 1058 | isFloat32Array: 'Float32Array', 1059 | isFloat64Array: 'Float64Array', 1060 | isFormData: 'FormData', 1061 | isFunction: 'Function', 1062 | isGenerator: 'Generator', 1063 | isGeneratorFunction: 'GeneratorFunction', 1064 | isHtmlElement: 'HTMLElement', 1065 | isInfinite: 'infinite number', 1066 | isInRange: 'in range', 1067 | isInt16Array: 'Int16Array', 1068 | isInt32Array: 'Int32Array', 1069 | isInt8Array: 'Int8Array', 1070 | isInteger: 'integer', 1071 | isIterable: 'Iterable', 1072 | isMap: 'Map', 1073 | isNan: 'NaN', 1074 | isNativePromise: 'native Promise', 1075 | isNegativeNumber: 'negative number', 1076 | isNodeStream: 'Node.js Stream', 1077 | isNonEmptyArray: 'non-empty array', 1078 | isNonEmptyMap: 'non-empty map', 1079 | isNonEmptyObject: 'non-empty object', 1080 | isNonEmptySet: 'non-empty set', 1081 | isNonEmptyString: 'non-empty string', 1082 | isNonEmptyStringAndNotWhitespace: 'non-empty string and not whitespace', 1083 | isNull: 'null', 1084 | isNullOrUndefined: 'null or undefined', 1085 | isNumber: 'number', 1086 | isNumericString: 'string with a number', 1087 | isObject: 'Object', 1088 | isObservable: 'Observable', 1089 | isOddInteger: 'odd integer', 1090 | isPlainObject: 'plain object', 1091 | isPositiveNumber: 'positive number', 1092 | isPrimitive: 'primitive', 1093 | isPromise: 'Promise', 1094 | isPropertyKey: 'PropertyKey', 1095 | isRegExp: 'RegExp', 1096 | isSafeInteger: 'integer', 1097 | isSet: 'Set', 1098 | isSharedArrayBuffer: 'SharedArrayBuffer', 1099 | isString: 'string', 1100 | isSymbol: 'symbol', 1101 | isTruthy: 'truthy', 1102 | isTupleLike: 'tuple-like', 1103 | isTypedArray: 'TypedArray', 1104 | isUint16Array: 'Uint16Array', 1105 | isUint32Array: 'Uint32Array', 1106 | isUint8Array: 'Uint8Array', 1107 | isUint8ClampedArray: 'Uint8ClampedArray', 1108 | isUndefined: 'undefined', 1109 | isUrlInstance: 'URL', 1110 | isUrlSearchParams: 'URLSearchParams', 1111 | isUrlString: 'string with a URL', 1112 | isValidDate: 'valid Date', 1113 | isValidLength: 'valid length', 1114 | isWeakMap: 'WeakMap', 1115 | isWeakRef: 'WeakRef', 1116 | isWeakSet: 'WeakSet', 1117 | isWhitespaceString: 'whitespace string', 1118 | } as const; 1119 | 1120 | function keysOf>(value: T): Array { 1121 | return Object.keys(value) as Array; 1122 | } 1123 | 1124 | type IsMethodName = keyof typeof methodTypeMap; 1125 | const isMethodNames: IsMethodName[] = keysOf(methodTypeMap); 1126 | 1127 | function isIsMethodName(value: unknown): value is IsMethodName { 1128 | return isMethodNames.includes(value as IsMethodName); 1129 | } 1130 | 1131 | export function assertAll(predicate: Predicate, ...values: unknown[]): void | never { 1132 | if (!isAll(predicate, ...values)) { 1133 | const expectedType = isIsMethodName(predicate.name) ? methodTypeMap[predicate.name] : 'predicate returns truthy for all values'; 1134 | throw new TypeError(typeErrorMessageMultipleValues(expectedType, values)); 1135 | } 1136 | } 1137 | 1138 | export function assertAny(predicate: Predicate | Predicate[], ...values: unknown[]): void | never { 1139 | if (!isAny(predicate, ...values)) { 1140 | const predicates = isArray(predicate) ? predicate : [predicate]; 1141 | const expectedTypes = predicates.map(predicate => isIsMethodName(predicate.name) ? methodTypeMap[predicate.name] : 'predicate returns truthy for any value'); 1142 | throw new TypeError(typeErrorMessageMultipleValues(expectedTypes, values)); 1143 | } 1144 | } 1145 | 1146 | export function assertArray(value: unknown, assertion?: (element: unknown, message?: string) => asserts element is T, message?: string): asserts value is T[] { 1147 | if (!isArray(value)) { 1148 | throw new TypeError(message ?? typeErrorMessage('Array', value)); 1149 | } 1150 | 1151 | if (assertion) { 1152 | for (const element of value) { 1153 | // @ts-expect-error: "Assertions require every name in the call target to be declared with an explicit type annotation." 1154 | assertion(element, message); 1155 | } 1156 | } 1157 | } 1158 | 1159 | export function assertArrayBuffer(value: unknown, message?: string): asserts value is ArrayBuffer { 1160 | if (!isArrayBuffer(value)) { 1161 | throw new TypeError(message ?? typeErrorMessage('ArrayBuffer', value)); 1162 | } 1163 | } 1164 | 1165 | export function assertArrayLike(value: unknown, message?: string): asserts value is ArrayLike { 1166 | if (!isArrayLike(value)) { 1167 | throw new TypeError(message ?? typeErrorMessage('array-like', value)); 1168 | } 1169 | } 1170 | 1171 | // eslint-disable-next-line @typescript-eslint/ban-types 1172 | export function assertAsyncFunction(value: unknown, message?: string): asserts value is Function { 1173 | if (!isAsyncFunction(value)) { 1174 | throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value)); 1175 | } 1176 | } 1177 | 1178 | export function assertAsyncGenerator(value: unknown, message?: string): asserts value is AsyncGenerator { 1179 | if (!isAsyncGenerator(value)) { 1180 | throw new TypeError(message ?? typeErrorMessage('AsyncGenerator', value)); 1181 | } 1182 | } 1183 | 1184 | export function assertAsyncGeneratorFunction(value: unknown, message?: string): asserts value is AsyncGeneratorFunction { 1185 | if (!isAsyncGeneratorFunction(value)) { 1186 | throw new TypeError(message ?? typeErrorMessage('AsyncGeneratorFunction', value)); 1187 | } 1188 | } 1189 | 1190 | export function assertAsyncIterable(value: unknown, message?: string): asserts value is AsyncIterable { 1191 | if (!isAsyncIterable(value)) { 1192 | throw new TypeError(message ?? typeErrorMessage('AsyncIterable', value)); 1193 | } 1194 | } 1195 | 1196 | export function assertBigint(value: unknown, message?: string): asserts value is bigint { 1197 | if (!isBigint(value)) { 1198 | throw new TypeError(message ?? typeErrorMessage('bigint', value)); 1199 | } 1200 | } 1201 | 1202 | export function assertBigInt64Array(value: unknown, message?: string): asserts value is BigInt64Array { 1203 | if (!isBigInt64Array(value)) { 1204 | throw new TypeError(message ?? typeErrorMessage('BigInt64Array', value)); 1205 | } 1206 | } 1207 | 1208 | export function assertBigUint64Array(value: unknown, message?: string): asserts value is BigUint64Array { 1209 | if (!isBigUint64Array(value)) { 1210 | throw new TypeError(message ?? typeErrorMessage('BigUint64Array', value)); 1211 | } 1212 | } 1213 | 1214 | export function assertBlob(value: unknown, message?: string): asserts value is Blob { 1215 | if (!isBlob(value)) { 1216 | throw new TypeError(message ?? typeErrorMessage('Blob', value)); 1217 | } 1218 | } 1219 | 1220 | export function assertBoolean(value: unknown, message?: string): asserts value is boolean { 1221 | if (!isBoolean(value)) { 1222 | throw new TypeError(message ?? typeErrorMessage('boolean', value)); 1223 | } 1224 | } 1225 | 1226 | // eslint-disable-next-line @typescript-eslint/ban-types 1227 | export function assertBoundFunction(value: unknown, message?: string): asserts value is Function { 1228 | if (!isBoundFunction(value)) { 1229 | throw new TypeError(message ?? typeErrorMessage('Function', value)); 1230 | } 1231 | } 1232 | 1233 | /** 1234 | Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) 1235 | */ 1236 | export function assertBuffer(value: unknown, message?: string): asserts value is NodeBuffer { 1237 | if (!isBuffer(value)) { 1238 | throw new TypeError(message ?? typeErrorMessage('Buffer', value)); 1239 | } 1240 | } 1241 | 1242 | export function assertClass(value: unknown, message?: string): asserts value is Class { 1243 | if (!isClass(value)) { 1244 | throw new TypeError(message ?? typeErrorMessage('Class', value)); 1245 | } 1246 | } 1247 | 1248 | export function assertDataView(value: unknown, message?: string): asserts value is DataView { 1249 | if (!isDataView(value)) { 1250 | throw new TypeError(message ?? typeErrorMessage('DataView', value)); 1251 | } 1252 | } 1253 | 1254 | export function assertDate(value: unknown, message?: string): asserts value is Date { 1255 | if (!isDate(value)) { 1256 | throw new TypeError(message ?? typeErrorMessage('Date', value)); 1257 | } 1258 | } 1259 | 1260 | export function assertDirectInstanceOf(instance: unknown, class_: Class, message?: string): asserts instance is T { 1261 | if (!isDirectInstanceOf(instance, class_)) { 1262 | throw new TypeError(message ?? typeErrorMessage('T', instance)); 1263 | } 1264 | } 1265 | 1266 | export function assertEmptyArray(value: unknown, message?: string): asserts value is never[] { 1267 | if (!isEmptyArray(value)) { 1268 | throw new TypeError(message ?? typeErrorMessage('empty array', value)); 1269 | } 1270 | } 1271 | 1272 | export function assertEmptyMap(value: unknown, message?: string): asserts value is Map { 1273 | if (!isEmptyMap(value)) { 1274 | throw new TypeError(message ?? typeErrorMessage('empty map', value)); 1275 | } 1276 | } 1277 | 1278 | export function assertEmptyObject(value: unknown, message?: string): asserts value is Record { 1279 | if (!isEmptyObject(value)) { 1280 | throw new TypeError(message ?? typeErrorMessage('empty object', value)); 1281 | } 1282 | } 1283 | 1284 | export function assertEmptySet(value: unknown, message?: string): asserts value is Set { 1285 | if (!isEmptySet(value)) { 1286 | throw new TypeError(message ?? typeErrorMessage('empty set', value)); 1287 | } 1288 | } 1289 | 1290 | export function assertEmptyString(value: unknown, message?: string): asserts value is '' { 1291 | if (!isEmptyString(value)) { 1292 | throw new TypeError(message ?? typeErrorMessage('empty string', value)); 1293 | } 1294 | } 1295 | 1296 | export function assertEmptyStringOrWhitespace(value: unknown, message?: string): asserts value is '' | Whitespace { 1297 | if (!isEmptyStringOrWhitespace(value)) { 1298 | throw new TypeError(message ?? typeErrorMessage('empty string or whitespace', value)); 1299 | } 1300 | } 1301 | 1302 | export function assertEnumCase(value: unknown, targetEnum: T, message?: string): asserts value is T[keyof T] { 1303 | if (!isEnumCase(value, targetEnum)) { 1304 | throw new TypeError(message ?? typeErrorMessage('EnumCase', value)); 1305 | } 1306 | } 1307 | 1308 | export function assertError(value: unknown, message?: string): asserts value is Error { 1309 | if (!isError(value)) { 1310 | throw new TypeError(message ?? typeErrorMessage('Error', value)); 1311 | } 1312 | } 1313 | 1314 | export function assertEvenInteger(value: number, message?: string): asserts value is number { 1315 | if (!isEvenInteger(value)) { 1316 | throw new TypeError(message ?? typeErrorMessage('even integer', value)); 1317 | } 1318 | } 1319 | 1320 | export function assertFalsy(value: unknown, message?: string): asserts value is Falsy { 1321 | if (!isFalsy(value)) { 1322 | throw new TypeError(message ?? typeErrorMessage('falsy', value)); 1323 | } 1324 | } 1325 | 1326 | export function assertFloat32Array(value: unknown, message?: string): asserts value is Float32Array { 1327 | if (!isFloat32Array(value)) { 1328 | throw new TypeError(message ?? typeErrorMessage('Float32Array', value)); 1329 | } 1330 | } 1331 | 1332 | export function assertFloat64Array(value: unknown, message?: string): asserts value is Float64Array { 1333 | if (!isFloat64Array(value)) { 1334 | throw new TypeError(message ?? typeErrorMessage('Float64Array', value)); 1335 | } 1336 | } 1337 | 1338 | export function assertFormData(value: unknown, message?: string): asserts value is FormData { 1339 | if (!isFormData(value)) { 1340 | throw new TypeError(message ?? typeErrorMessage('FormData', value)); 1341 | } 1342 | } 1343 | 1344 | // eslint-disable-next-line @typescript-eslint/ban-types 1345 | export function assertFunction(value: unknown, message?: string): asserts value is Function { 1346 | if (!isFunction(value)) { 1347 | throw new TypeError(message ?? typeErrorMessage('Function', value)); 1348 | } 1349 | } 1350 | 1351 | export function assertGenerator(value: unknown, message?: string): asserts value is Generator { 1352 | if (!isGenerator(value)) { 1353 | throw new TypeError(message ?? typeErrorMessage('Generator', value)); 1354 | } 1355 | } 1356 | 1357 | export function assertGeneratorFunction(value: unknown, message?: string): asserts value is GeneratorFunction { 1358 | if (!isGeneratorFunction(value)) { 1359 | throw new TypeError(message ?? typeErrorMessage('GeneratorFunction', value)); 1360 | } 1361 | } 1362 | 1363 | export function assertHtmlElement(value: unknown, message?: string): asserts value is HTMLElement { 1364 | if (!isHtmlElement(value)) { 1365 | throw new TypeError(message ?? typeErrorMessage('HTMLElement', value)); 1366 | } 1367 | } 1368 | 1369 | export function assertInfinite(value: unknown, message?: string): asserts value is number { 1370 | if (!isInfinite(value)) { 1371 | throw new TypeError(message ?? typeErrorMessage('infinite number', value)); 1372 | } 1373 | } 1374 | 1375 | export function assertInRange(value: number, range: number | [number, number], message?: string): asserts value is number { 1376 | if (!isInRange(value, range)) { 1377 | throw new TypeError(message ?? typeErrorMessage('in range', value)); 1378 | } 1379 | } 1380 | 1381 | export function assertInt16Array(value: unknown, message?: string): asserts value is Int16Array { 1382 | if (!isInt16Array(value)) { 1383 | throw new TypeError(message ?? typeErrorMessage('Int16Array', value)); 1384 | } 1385 | } 1386 | 1387 | export function assertInt32Array(value: unknown, message?: string): asserts value is Int32Array { 1388 | if (!isInt32Array(value)) { 1389 | throw new TypeError(message ?? typeErrorMessage('Int32Array', value)); 1390 | } 1391 | } 1392 | 1393 | export function assertInt8Array(value: unknown, message?: string): asserts value is Int8Array { 1394 | if (!isInt8Array(value)) { 1395 | throw new TypeError(message ?? typeErrorMessage('Int8Array', value)); 1396 | } 1397 | } 1398 | 1399 | export function assertInteger(value: unknown, message?: string): asserts value is number { 1400 | if (!isInteger(value)) { 1401 | throw new TypeError(message ?? typeErrorMessage('integer', value)); 1402 | } 1403 | } 1404 | 1405 | export function assertIterable(value: unknown, message?: string): asserts value is Iterable { 1406 | if (!isIterable(value)) { 1407 | throw new TypeError(message ?? typeErrorMessage('Iterable', value)); 1408 | } 1409 | } 1410 | 1411 | export function assertMap(value: unknown, message?: string): asserts value is Map { 1412 | if (!isMap(value)) { 1413 | throw new TypeError(message ?? typeErrorMessage('Map', value)); 1414 | } 1415 | } 1416 | 1417 | export function assertNan(value: unknown, message?: string): asserts value is number { 1418 | if (!isNan(value)) { 1419 | throw new TypeError(message ?? typeErrorMessage('NaN', value)); 1420 | } 1421 | } 1422 | 1423 | export function assertNativePromise(value: unknown, message?: string): asserts value is Promise { 1424 | if (!isNativePromise(value)) { 1425 | throw new TypeError(message ?? typeErrorMessage('native Promise', value)); 1426 | } 1427 | } 1428 | 1429 | export function assertNegativeNumber(value: unknown, message?: string): asserts value is number { 1430 | if (!isNegativeNumber(value)) { 1431 | throw new TypeError(message ?? typeErrorMessage('negative number', value)); 1432 | } 1433 | } 1434 | 1435 | export function assertNodeStream(value: unknown, message?: string): asserts value is NodeStream { 1436 | if (!isNodeStream(value)) { 1437 | throw new TypeError(message ?? typeErrorMessage('Node.js Stream', value)); 1438 | } 1439 | } 1440 | 1441 | export function assertNonEmptyArray(value: T | Item[], message?: string): asserts value is [Item, ...Item[]] { 1442 | if (!isNonEmptyArray(value)) { 1443 | throw new TypeError(message ?? typeErrorMessage('non-empty array', value)); 1444 | } 1445 | } 1446 | 1447 | export function assertNonEmptyMap(value: unknown, message?: string): asserts value is Map { 1448 | if (!isNonEmptyMap(value)) { 1449 | throw new TypeError(message ?? typeErrorMessage('non-empty map', value)); 1450 | } 1451 | } 1452 | 1453 | export function assertNonEmptyObject(value: unknown, message?: string): asserts value is Record { 1454 | if (!isNonEmptyObject(value)) { 1455 | throw new TypeError(message ?? typeErrorMessage('non-empty object', value)); 1456 | } 1457 | } 1458 | 1459 | export function assertNonEmptySet(value: unknown, message?: string): asserts value is Set { 1460 | if (!isNonEmptySet(value)) { 1461 | throw new TypeError(message ?? typeErrorMessage('non-empty set', value)); 1462 | } 1463 | } 1464 | 1465 | export function assertNonEmptyString(value: unknown, message?: string): asserts value is string { 1466 | if (!isNonEmptyString(value)) { 1467 | throw new TypeError(message ?? typeErrorMessage('non-empty string', value)); 1468 | } 1469 | } 1470 | 1471 | export function assertNonEmptyStringAndNotWhitespace(value: unknown, message?: string): asserts value is string { 1472 | if (!isNonEmptyStringAndNotWhitespace(value)) { 1473 | throw new TypeError(message ?? typeErrorMessage('non-empty string and not whitespace', value)); 1474 | } 1475 | } 1476 | 1477 | // eslint-disable-next-line @typescript-eslint/ban-types 1478 | export function assertNull(value: unknown, message?: string): asserts value is null { 1479 | if (!isNull(value)) { 1480 | throw new TypeError(message ?? typeErrorMessage('null', value)); 1481 | } 1482 | } 1483 | 1484 | // eslint-disable-next-line @typescript-eslint/ban-types 1485 | export function assertNullOrUndefined(value: unknown, message?: string): asserts value is null | undefined { 1486 | if (!isNullOrUndefined(value)) { 1487 | throw new TypeError(message ?? typeErrorMessage('null or undefined', value)); 1488 | } 1489 | } 1490 | 1491 | export function assertNumber(value: unknown, message?: string): asserts value is number { 1492 | if (!isNumber(value)) { 1493 | throw new TypeError(message ?? typeErrorMessage('number', value)); 1494 | } 1495 | } 1496 | 1497 | export function assertNumericString(value: unknown, message?: string): asserts value is `${number}` { 1498 | if (!isNumericString(value)) { 1499 | throw new TypeError(message ?? typeErrorMessage('string with a number', value)); 1500 | } 1501 | } 1502 | 1503 | // eslint-disable-next-line @typescript-eslint/ban-types 1504 | export function assertObject(value: unknown, message?: string): asserts value is object { 1505 | if (!isObject(value)) { 1506 | throw new TypeError(message ?? typeErrorMessage('Object', value)); 1507 | } 1508 | } 1509 | 1510 | export function assertObservable(value: unknown, message?: string): asserts value is ObservableLike { 1511 | if (!isObservable(value)) { 1512 | throw new TypeError(message ?? typeErrorMessage('Observable', value)); 1513 | } 1514 | } 1515 | 1516 | export function assertOddInteger(value: number, message?: string): asserts value is number { 1517 | if (!isOddInteger(value)) { 1518 | throw new TypeError(message ?? typeErrorMessage('odd integer', value)); 1519 | } 1520 | } 1521 | 1522 | export function assertPlainObject(value: unknown, message?: string): asserts value is Record { 1523 | if (!isPlainObject(value)) { 1524 | throw new TypeError(message ?? typeErrorMessage('plain object', value)); 1525 | } 1526 | } 1527 | 1528 | export function assertPositiveNumber(value: unknown, message?: string): asserts value is number { 1529 | if (!isPositiveNumber(value)) { 1530 | throw new TypeError(message ?? typeErrorMessage('positive number', value)); 1531 | } 1532 | } 1533 | 1534 | export function assertPrimitive(value: unknown, message?: string): asserts value is Primitive { 1535 | if (!isPrimitive(value)) { 1536 | throw new TypeError(message ?? typeErrorMessage('primitive', value)); 1537 | } 1538 | } 1539 | 1540 | export function assertPromise(value: unknown, message?: string): asserts value is Promise { 1541 | if (!isPromise(value)) { 1542 | throw new TypeError(message ?? typeErrorMessage('Promise', value)); 1543 | } 1544 | } 1545 | 1546 | export function assertPropertyKey(value: unknown, message?: string): asserts value is number { 1547 | if (!isPropertyKey(value)) { 1548 | throw new TypeError(message ?? typeErrorMessage('PropertyKey', value)); 1549 | } 1550 | } 1551 | 1552 | export function assertRegExp(value: unknown, message?: string): asserts value is RegExp { 1553 | if (!isRegExp(value)) { 1554 | throw new TypeError(message ?? typeErrorMessage('RegExp', value)); 1555 | } 1556 | } 1557 | 1558 | export function assertSafeInteger(value: unknown, message?: string): asserts value is number { 1559 | if (!isSafeInteger(value)) { 1560 | throw new TypeError(message ?? typeErrorMessage('integer', value)); 1561 | } 1562 | } 1563 | 1564 | export function assertSet(value: unknown, message?: string): asserts value is Set { 1565 | if (!isSet(value)) { 1566 | throw new TypeError(message ?? typeErrorMessage('Set', value)); 1567 | } 1568 | } 1569 | 1570 | export function assertSharedArrayBuffer(value: unknown, message?: string): asserts value is SharedArrayBuffer { 1571 | if (!isSharedArrayBuffer(value)) { 1572 | throw new TypeError(message ?? typeErrorMessage('SharedArrayBuffer', value)); 1573 | } 1574 | } 1575 | 1576 | export function assertString(value: unknown, message?: string): asserts value is string { 1577 | if (!isString(value)) { 1578 | throw new TypeError(message ?? typeErrorMessage('string', value)); 1579 | } 1580 | } 1581 | 1582 | export function assertSymbol(value: unknown, message?: string): asserts value is symbol { 1583 | if (!isSymbol(value)) { 1584 | throw new TypeError(message ?? typeErrorMessage('symbol', value)); 1585 | } 1586 | } 1587 | 1588 | export function assertTruthy(value: T | Falsy, message?: string): asserts value is T { 1589 | if (!isTruthy(value)) { 1590 | throw new TypeError(message ?? typeErrorMessage('truthy', value)); 1591 | } 1592 | } 1593 | 1594 | export function assertTupleLike>>(value: unknown, guards: [...T], message?: string): asserts value is ResolveTypesOfTypeGuardsTuple { 1595 | if (!isTupleLike(value, guards)) { 1596 | throw new TypeError(message ?? typeErrorMessage('tuple-like', value)); 1597 | } 1598 | } 1599 | 1600 | export function assertTypedArray(value: unknown, message?: string): asserts value is TypedArray { 1601 | if (!isTypedArray(value)) { 1602 | throw new TypeError(message ?? typeErrorMessage('TypedArray', value)); 1603 | } 1604 | } 1605 | 1606 | export function assertUint16Array(value: unknown, message?: string): asserts value is Uint16Array { 1607 | if (!isUint16Array(value)) { 1608 | throw new TypeError(message ?? typeErrorMessage('Uint16Array', value)); 1609 | } 1610 | } 1611 | 1612 | export function assertUint32Array(value: unknown, message?: string): asserts value is Uint32Array { 1613 | if (!isUint32Array(value)) { 1614 | throw new TypeError(message ?? typeErrorMessage('Uint32Array', value)); 1615 | } 1616 | } 1617 | 1618 | export function assertUint8Array(value: unknown, message?: string): asserts value is Uint8Array { 1619 | if (!isUint8Array(value)) { 1620 | throw new TypeError(message ?? typeErrorMessage('Uint8Array', value)); 1621 | } 1622 | } 1623 | 1624 | export function assertUint8ClampedArray(value: unknown, message?: string): asserts value is Uint8ClampedArray { 1625 | if (!isUint8ClampedArray(value)) { 1626 | throw new TypeError(message ?? typeErrorMessage('Uint8ClampedArray', value)); 1627 | } 1628 | } 1629 | 1630 | export function assertUndefined(value: unknown, message?: string): asserts value is undefined { 1631 | if (!isUndefined(value)) { 1632 | throw new TypeError(message ?? typeErrorMessage('undefined', value)); 1633 | } 1634 | } 1635 | 1636 | export function assertUrlInstance(value: unknown, message?: string): asserts value is URL { 1637 | if (!isUrlInstance(value)) { 1638 | throw new TypeError(message ?? typeErrorMessage('URL', value)); 1639 | } 1640 | } 1641 | 1642 | // eslint-disable-next-line unicorn/prevent-abbreviations 1643 | export function assertUrlSearchParams(value: unknown, message?: string): asserts value is URLSearchParams { 1644 | if (!isUrlSearchParams(value)) { 1645 | throw new TypeError(message ?? typeErrorMessage('URLSearchParams', value)); 1646 | } 1647 | } 1648 | 1649 | export function assertUrlString(value: unknown, message?: string): asserts value is string { 1650 | if (!isUrlString(value)) { 1651 | throw new TypeError(message ?? typeErrorMessage('string with a URL', value)); 1652 | } 1653 | } 1654 | 1655 | export function assertValidDate(value: unknown, message?: string): asserts value is Date { 1656 | if (!isValidDate(value)) { 1657 | throw new TypeError(message ?? typeErrorMessage('valid Date', value)); 1658 | } 1659 | } 1660 | 1661 | export function assertValidLength(value: unknown, message?: string): asserts value is number { 1662 | if (!isValidLength(value)) { 1663 | throw new TypeError(message ?? typeErrorMessage('valid length', value)); 1664 | } 1665 | } 1666 | 1667 | // eslint-disable-next-line @typescript-eslint/ban-types 1668 | export function assertWeakMap(value: unknown, message?: string): asserts value is WeakMap { 1669 | if (!isWeakMap(value)) { 1670 | throw new TypeError(message ?? typeErrorMessage('WeakMap', value)); 1671 | } 1672 | } 1673 | 1674 | // eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations 1675 | export function assertWeakRef(value: unknown, message?: string): asserts value is WeakRef { 1676 | if (!isWeakRef(value)) { 1677 | throw new TypeError(message ?? typeErrorMessage('WeakRef', value)); 1678 | } 1679 | } 1680 | 1681 | // eslint-disable-next-line @typescript-eslint/ban-types 1682 | export function assertWeakSet(value: unknown, message?: string): asserts value is WeakSet { 1683 | if (!isWeakSet(value)) { 1684 | throw new TypeError(message ?? typeErrorMessage('WeakSet', value)); 1685 | } 1686 | } 1687 | 1688 | export function assertWhitespaceString(value: unknown, message?: string): asserts value is string { 1689 | if (!isWhitespaceString(value)) { 1690 | throw new TypeError(message ?? typeErrorMessage('whitespace string', value)); 1691 | } 1692 | } 1693 | 1694 | export default is; 1695 | 1696 | export type { 1697 | ArrayLike, 1698 | Class, 1699 | NodeStream, 1700 | ObservableLike, 1701 | Predicate, 1702 | Primitive, 1703 | TypedArray, 1704 | } from './types.js'; 1705 | -------------------------------------------------------------------------------- /source/types.ts: -------------------------------------------------------------------------------- 1 | // Extracted from https://github.com/sindresorhus/type-fest/blob/78019f42ea888b0cdceb41a4a78163868de57555/index.d.ts 2 | 3 | /** 4 | Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive). 5 | */ 6 | export type Primitive = 7 | | null // eslint-disable-line @typescript-eslint/ban-types 8 | | undefined 9 | | string 10 | | number 11 | | boolean 12 | | symbol 13 | | bigint; 14 | 15 | /** 16 | Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). 17 | */ 18 | type Constructor = new(...arguments_: Arguments) => T; 19 | 20 | /** 21 | Matches a [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). 22 | */ 23 | export type Class = Constructor & {prototype: T}; 24 | 25 | /** 26 | Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`. 27 | */ 28 | export type TypedArray = 29 | | Int8Array 30 | | Uint8Array 31 | | Uint8ClampedArray 32 | | Int16Array 33 | | Uint16Array 34 | | Int32Array 35 | | Uint32Array 36 | | Float32Array 37 | | Float64Array 38 | | BigInt64Array 39 | | BigUint64Array; 40 | 41 | declare global { 42 | // eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- This must be an `interface` so it can be merged. 43 | interface SymbolConstructor { 44 | readonly observable: symbol; 45 | } 46 | } 47 | 48 | /** 49 | Matches a value that is like an [Observable](https://github.com/tc39/proposal-observable). 50 | */ 51 | export type ObservableLike = { 52 | subscribe(observer: (value: unknown) => void): void; 53 | [Symbol.observable](): ObservableLike; 54 | }; 55 | 56 | // eslint-disable-next-line @typescript-eslint/ban-types 57 | export type Falsy = false | 0 | 0n | '' | null | undefined; 58 | 59 | export type WeakRef = { // eslint-disable-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations 60 | readonly [Symbol.toStringTag]: 'WeakRef'; 61 | deref(): T | undefined; 62 | }; 63 | 64 | export type ArrayLike = { 65 | readonly [index: number]: T; 66 | readonly length: number; 67 | }; 68 | 69 | export type NodeStream = { 70 | pipe(destination: T, options?: {end?: boolean}): T; 71 | } & NodeJS.EventEmitter; 72 | 73 | export type Predicate = (value: unknown) => boolean; 74 | 75 | export type NonEmptyString = string & {0: string}; 76 | 77 | export type Whitespace = ' '; 78 | -------------------------------------------------------------------------------- /test/test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-function */ 2 | import {Buffer} from 'node:buffer'; 3 | import fs from 'node:fs'; 4 | import net from 'node:net'; 5 | import Stream from 'node:stream'; 6 | import {inspect} from 'node:util'; 7 | import test, {type ExecutionContext} from 'ava'; 8 | import {JSDOM} from 'jsdom'; 9 | import {Subject, Observable} from 'rxjs'; 10 | import {temporaryFile} from 'tempy'; 11 | import {expectTypeOf} from 'expect-type'; 12 | import ZenObservable from 'zen-observable'; 13 | import is, { 14 | assert, 15 | type AssertionTypeDescription, 16 | type Primitive, 17 | type TypedArray, 18 | type TypeName, 19 | } from '../source/index.js'; 20 | 21 | class PromiseSubclassFixture extends Promise {} 22 | class ErrorSubclassFixture extends Error {} 23 | 24 | const {window} = new JSDOM(); 25 | const {document} = window; 26 | 27 | const structuredClone = globalThis.structuredClone ?? (x => x); 28 | 29 | type Test = { 30 | assert: (...arguments_: any[]) => void | never; 31 | fixtures: unknown[]; 32 | typename?: TypeName; 33 | typeDescription?: AssertionTypeDescription; 34 | is(value: unknown): boolean; 35 | }; 36 | 37 | const invertAssertThrow = (description: AssertionTypeDescription, function_: () => void | never, value: unknown): void | never => { 38 | const expectedAssertErrorMessage = `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`; 39 | 40 | try { 41 | function_(); 42 | } catch (error: unknown) { 43 | if (error instanceof TypeError && error.message.includes(expectedAssertErrorMessage)) { 44 | return; 45 | } 46 | 47 | throw error; 48 | } 49 | 50 | throw new Error(`Function did not throw any error, expected: ${expectedAssertErrorMessage}`); 51 | }; 52 | 53 | const types = new Map([ 54 | ['undefined', { 55 | is: is.undefined, 56 | assert: assert.undefined, 57 | fixtures: [ 58 | undefined, 59 | ], 60 | typename: 'undefined', 61 | }], 62 | ['null', { 63 | is: is.null, 64 | assert: assert.null, 65 | fixtures: [ 66 | null, 67 | ], 68 | typename: 'null', 69 | }], 70 | ['string', { 71 | is: is.string, 72 | assert: assert.string, 73 | fixtures: [ 74 | '🦄', 75 | 'hello world', 76 | '', 77 | ], 78 | typename: 'string', 79 | }], 80 | ['emptyString', { 81 | is: is.emptyString, 82 | assert: assert.emptyString, 83 | fixtures: [ 84 | '', 85 | String(), 86 | ], 87 | typename: 'string', 88 | typeDescription: 'empty string', 89 | }], 90 | ['number', { 91 | is: is.number, 92 | assert: assert.number, 93 | fixtures: [ 94 | 6, 95 | 1.4, 96 | 0, 97 | -0, 98 | Number.POSITIVE_INFINITY, 99 | Number.NEGATIVE_INFINITY, 100 | ], 101 | typename: 'number', 102 | }], 103 | ['bigint', { 104 | is: is.bigint, 105 | assert: assert.bigint, 106 | fixtures: [ 107 | // Disabled until TS supports it for an ESnnnn target. 108 | // 1n, 109 | // 0n, 110 | // -0n, 111 | BigInt('1234'), 112 | ], 113 | typename: 'bigint', 114 | }], 115 | ['boolean', { 116 | is: is.boolean, 117 | assert: assert.boolean, 118 | fixtures: [ 119 | true, false, 120 | ], 121 | typename: 'boolean', 122 | }], 123 | ['symbol', { 124 | is: is.symbol, 125 | assert: assert.symbol, 126 | fixtures: [ 127 | Symbol('🦄'), 128 | ], 129 | typename: 'symbol', 130 | }], 131 | ['numericString', { 132 | is: is.numericString, 133 | assert: assert.numericString, 134 | fixtures: [ 135 | '5', 136 | '-3.2', 137 | 'Infinity', 138 | '0x56', 139 | ], 140 | typename: 'string', 141 | typeDescription: 'string with a number', 142 | }], 143 | ['array', { 144 | is: is.array, 145 | assert: assert.array, 146 | fixtures: [ 147 | [1, 2], 148 | Array.from({length: 2}), 149 | ], 150 | typename: 'Array', 151 | }], 152 | ['emptyArray', { 153 | is: is.emptyArray, 154 | assert: assert.emptyArray, 155 | fixtures: [ 156 | [], 157 | new Array(), // eslint-disable-line @typescript-eslint/no-array-constructor 158 | ], 159 | typename: 'Array', 160 | typeDescription: 'empty array', 161 | }], 162 | ['function', { 163 | is: is.function, 164 | assert: assert.function, 165 | fixtures: [ 166 | function foo() {}, // eslint-disable-line func-names 167 | function () {}, 168 | () => {}, 169 | async function () {}, 170 | function * (): unknown {}, 171 | async function * (): unknown {}, 172 | ], 173 | typename: 'Function', 174 | }], 175 | ['buffer', { 176 | is: is.buffer, 177 | assert: assert.buffer, 178 | fixtures: [ 179 | Buffer.from('🦄'), 180 | ], 181 | typename: 'Buffer', 182 | }], 183 | ['blob', { 184 | is: is.blob, 185 | assert: assert.blob, 186 | fixtures: [ 187 | new window.Blob(), 188 | ], 189 | typename: 'Blob', 190 | }], 191 | ['object', { 192 | is: is.object, 193 | assert: assert.object, 194 | fixtures: [ 195 | {x: 1}, 196 | Object.create({x: 1}), 197 | ], 198 | typename: 'Object', 199 | }], 200 | ['regExp', { 201 | is: is.regExp, 202 | assert: assert.regExp, 203 | fixtures: [ 204 | /\w/, 205 | new RegExp('\\w'), // eslint-disable-line prefer-regex-literals 206 | ], 207 | typename: 'RegExp', 208 | }], 209 | ['date', { 210 | is: is.date, 211 | assert: assert.date, 212 | fixtures: [ 213 | new Date(), 214 | ], 215 | typename: 'Date', 216 | }], 217 | ['error', { 218 | is: is.error, 219 | assert: assert.error, 220 | fixtures: [ 221 | new Error('🦄'), 222 | new ErrorSubclassFixture(), 223 | ], 224 | typename: 'Error', 225 | }], 226 | ['nativePromise', { 227 | is: is.nativePromise, 228 | assert: assert.nativePromise, 229 | fixtures: [ 230 | Promise.resolve(), 231 | PromiseSubclassFixture.resolve(), 232 | ], 233 | typename: 'Promise', 234 | typeDescription: 'native Promise', 235 | }], 236 | ['promise', { 237 | is: is.promise, 238 | assert: assert.promise, 239 | fixtures: [ 240 | {then() {}, catch() {}}, // eslint-disable-line unicorn/no-thenable 241 | ], 242 | typename: 'Object', 243 | typeDescription: 'Promise', 244 | }], 245 | ['generator', { 246 | is: is.generator, 247 | assert: assert.generator, 248 | fixtures: [ 249 | (function * () { 250 | yield 4; 251 | })(), 252 | ], 253 | typename: 'Generator', 254 | }], 255 | ['asyncGenerator', { 256 | is: is.asyncGenerator, 257 | assert: assert.asyncGenerator, 258 | fixtures: [ 259 | (async function * () { 260 | yield 4; 261 | })(), 262 | ], 263 | typename: 'AsyncGenerator', 264 | }], 265 | ['generatorFunction', { 266 | is: is.generatorFunction, 267 | assert: assert.generatorFunction, 268 | fixtures: [ 269 | function * () { 270 | yield 4; 271 | }, 272 | ], 273 | typename: 'Function', 274 | typeDescription: 'GeneratorFunction', 275 | }], 276 | ['asyncGeneratorFunction', { 277 | is: is.asyncGeneratorFunction, 278 | assert: assert.asyncGeneratorFunction, 279 | fixtures: [ 280 | async function * () { 281 | yield 4; 282 | }, 283 | ], 284 | typename: 'Function', 285 | typeDescription: 'AsyncGeneratorFunction', 286 | }], 287 | ['asyncFunction', { 288 | is: is.asyncFunction, 289 | assert: assert.asyncFunction, 290 | fixtures: [ 291 | async function () {}, 292 | async () => {}, 293 | ], 294 | typename: 'Function', 295 | typeDescription: 'AsyncFunction', 296 | }], 297 | ['boundFunction', { 298 | is: is.boundFunction, 299 | assert: assert.boundFunction, 300 | fixtures: [ 301 | () => {}, 302 | function () {}.bind(null), // eslint-disable-line no-extra-bind 303 | ], 304 | typename: 'Function', 305 | }], 306 | ['map', { 307 | is: is.map, 308 | assert: assert.map, 309 | fixtures: [ 310 | new Map([['one', '1']]), 311 | ], 312 | typename: 'Map', 313 | }], 314 | ['emptyMap', { 315 | is: is.emptyMap, 316 | assert: assert.emptyMap, 317 | fixtures: [ 318 | new Map(), 319 | ], 320 | typename: 'Map', 321 | typeDescription: 'empty map', 322 | }], 323 | ['set', { 324 | is: is.set, 325 | assert: assert.set, 326 | fixtures: [ 327 | new Set(['one']), 328 | ], 329 | typename: 'Set', 330 | }], 331 | ['emptySet', { 332 | is: is.emptySet, 333 | assert: assert.emptySet, 334 | fixtures: [ 335 | new Set(), 336 | ], 337 | typename: 'Set', 338 | typeDescription: 'empty set', 339 | }], 340 | ['weakSet', { 341 | is: is.weakSet, 342 | assert: assert.weakSet, 343 | fixtures: [ 344 | new WeakSet(), 345 | ], 346 | typename: 'WeakSet', 347 | }], 348 | ['weakRef', { 349 | is: is.weakRef, 350 | assert: assert.weakRef, 351 | fixtures: window.WeakRef ? [new window.WeakRef({})] : [], 352 | typename: 'WeakRef', 353 | }], 354 | ['weakMap', { 355 | is: is.weakMap, 356 | assert: assert.weakMap, 357 | fixtures: [ 358 | new WeakMap(), 359 | ], 360 | typename: 'WeakMap', 361 | }], 362 | ['int8Array', { 363 | is: is.int8Array, 364 | assert: assert.int8Array, 365 | fixtures: [ 366 | new Int8Array(), 367 | ], 368 | typename: 'Int8Array', 369 | }], 370 | ['uint8Array', { 371 | is: is.uint8Array, 372 | assert: assert.uint8Array, 373 | fixtures: [ 374 | new Uint8Array(), 375 | ], 376 | typename: 'Uint8Array', 377 | }], 378 | ['uint8ClampedArray', { 379 | is: is.uint8ClampedArray, 380 | assert: assert.uint8ClampedArray, 381 | fixtures: [ 382 | new Uint8ClampedArray(), 383 | ], 384 | typename: 'Uint8ClampedArray', 385 | }], 386 | ['int16Array', { 387 | is: is.int16Array, 388 | assert: assert.int16Array, 389 | fixtures: [ 390 | new Int16Array(), 391 | ], 392 | typename: 'Int16Array', 393 | }], 394 | ['uint16Array', { 395 | is: is.uint16Array, 396 | assert: assert.uint16Array, 397 | fixtures: [ 398 | new Uint16Array(), 399 | ], 400 | typename: 'Uint16Array', 401 | }], 402 | ['int32Array', { 403 | is: is.int32Array, 404 | assert: assert.int32Array, 405 | fixtures: [ 406 | new Int32Array(), 407 | ], 408 | typename: 'Int32Array', 409 | }], 410 | ['uint32Array', { 411 | is: is.uint32Array, 412 | assert: assert.uint32Array, 413 | fixtures: [ 414 | new Uint32Array(), 415 | ], 416 | typename: 'Uint32Array', 417 | }], 418 | ['float32Array', { 419 | is: is.float32Array, 420 | assert: assert.float32Array, 421 | fixtures: [ 422 | new Float32Array(), 423 | ], 424 | typename: 'Float32Array', 425 | }], 426 | ['float64Array', { 427 | is: is.float64Array, 428 | assert: assert.float64Array, 429 | fixtures: [ 430 | new Float64Array(), 431 | ], 432 | typename: 'Float64Array', 433 | }], 434 | ['bigInt64Array', { 435 | is: is.bigInt64Array, 436 | assert: assert.bigInt64Array, 437 | fixtures: [ 438 | new BigInt64Array(), 439 | ], 440 | typename: 'BigInt64Array', 441 | }], 442 | ['bigUint64Array', { 443 | is: is.bigUint64Array, 444 | assert: assert.bigUint64Array, 445 | fixtures: [ 446 | new BigUint64Array(), 447 | ], 448 | typename: 'BigUint64Array', 449 | }], 450 | ['arrayBuffer', { 451 | is: is.arrayBuffer, 452 | assert: assert.arrayBuffer, 453 | fixtures: [ 454 | new ArrayBuffer(10), 455 | ], 456 | typename: 'ArrayBuffer', 457 | }], 458 | ['dataView', { 459 | is: is.dataView, 460 | assert: assert.dataView, 461 | fixtures: [ 462 | new DataView(new ArrayBuffer(10)), 463 | ], 464 | typename: 'DataView', 465 | }], 466 | ['nan', { 467 | is: is.nan, 468 | assert: assert.nan, 469 | fixtures: [ 470 | NaN, // eslint-disable-line unicorn/prefer-number-properties 471 | Number.NaN, 472 | ], 473 | typename: 'NaN', 474 | typeDescription: 'NaN', 475 | }], 476 | ['nullOrUndefined', { 477 | is: is.nullOrUndefined, 478 | assert: assert.nullOrUndefined, 479 | fixtures: [ 480 | null, 481 | undefined, 482 | ], 483 | typeDescription: 'null or undefined', 484 | }], 485 | ['plainObject', { 486 | is: is.plainObject, 487 | assert: assert.plainObject, 488 | fixtures: [ 489 | {x: 1}, 490 | Object.create(null), 491 | new Object(), // eslint-disable-line no-object-constructor 492 | structuredClone({x: 1}), 493 | structuredClone(Object.create(null)), 494 | structuredClone(new Object()), // eslint-disable-line no-object-constructor 495 | ], 496 | typename: 'Object', 497 | typeDescription: 'plain object', 498 | }], 499 | ['integer', { 500 | is: is.integer, 501 | assert: assert.integer, 502 | fixtures: [ 503 | 6, 504 | ], 505 | typename: 'number', 506 | typeDescription: 'integer', 507 | }], 508 | ['safeInteger', { 509 | is: is.safeInteger, 510 | assert: assert.safeInteger, 511 | fixtures: [ 512 | (2 ** 53) - 1, 513 | -(2 ** 53) + 1, 514 | ], 515 | typename: 'number', 516 | typeDescription: 'integer', 517 | }], 518 | ['htmlElement', { 519 | is: is.htmlElement, 520 | assert: assert.htmlElement, 521 | fixtures: [ 522 | 'div', 523 | 'input', 524 | 'span', 525 | 'img', 526 | 'canvas', 527 | 'script', 528 | ] 529 | .map(fixture => document.createElement(fixture)), 530 | typeDescription: 'HTMLElement', 531 | }], 532 | ['non-htmlElement', { 533 | is: value => !is.htmlElement(value), 534 | assert(value: unknown) { 535 | invertAssertThrow('HTMLElement', () => { 536 | assert.htmlElement(value); 537 | }, value); 538 | }, 539 | fixtures: [ 540 | document.createTextNode('data'), 541 | document.createProcessingInstruction('xml-stylesheet', 'href="mycss.css" type="text/css"'), 542 | document.createComment('This is a comment'), 543 | document, 544 | document.implementation.createDocumentType('svg:svg', '-//W3C//DTD SVG 1.1//EN', 'https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'), 545 | document.createDocumentFragment(), 546 | ], 547 | }], 548 | ['observable', { 549 | is: is.observable, 550 | assert: assert.observable, 551 | fixtures: [ 552 | new Observable(), 553 | new Subject(), 554 | new ZenObservable(() => {}), 555 | ], 556 | typename: 'Observable', 557 | }], 558 | ['nodeStream', { 559 | is: is.nodeStream, 560 | assert: assert.nodeStream, 561 | fixtures: [ 562 | fs.createReadStream('readme.md'), 563 | fs.createWriteStream(temporaryFile()), 564 | new net.Socket(), 565 | new Stream.Duplex(), 566 | new Stream.PassThrough(), 567 | new Stream.Readable(), 568 | new Stream.Transform(), 569 | new Stream.Stream(), 570 | new Stream.Writable(), 571 | ], 572 | typename: 'Object', 573 | typeDescription: 'Node.js Stream', 574 | }], 575 | ['infinite', { 576 | is: is.infinite, 577 | assert: assert.infinite, 578 | fixtures: [ 579 | Number.POSITIVE_INFINITY, 580 | Number.NEGATIVE_INFINITY, 581 | ], 582 | typename: 'number', 583 | typeDescription: 'infinite number', 584 | }], 585 | ]); 586 | 587 | // This ensures a certain method matches only the types it's supposed to and none of the other methods' types 588 | const testType = (t: ExecutionContext, type: string, exclude?: string[]) => { 589 | const testData = types.get(type); 590 | 591 | if (testData === undefined) { 592 | t.fail(`is.${type} not defined`); 593 | 594 | return; 595 | } 596 | 597 | const {is: testIs, assert: testAssert, typename, typeDescription} = testData; 598 | 599 | for (const [key, {fixtures}] of types) { 600 | // TODO: Automatically exclude value types in other tests that we have in the current one. 601 | // Could reduce the use of `exclude`. 602 | if (exclude?.includes(key)) { 603 | continue; 604 | } 605 | 606 | const isTypeUnderTest = key === type; 607 | const assertIs = isTypeUnderTest ? t.true : t.false; 608 | 609 | for (const fixture of fixtures) { 610 | assertIs(testIs(fixture), `Value: ${inspect(fixture)}`); 611 | const valueType = typeDescription ?? typename ?? 'unspecified'; 612 | 613 | if (isTypeUnderTest) { 614 | t.notThrows(() => { 615 | testAssert(fixture); 616 | }); 617 | } else { 618 | t.throws(() => { 619 | testAssert(fixture); 620 | }, { 621 | message: `Expected value which is \`${valueType}\`, received value of type \`${is(fixture)}\`.`, 622 | }); 623 | } 624 | 625 | if (isTypeUnderTest && typename) { 626 | t.is(is(fixture), typename); 627 | } 628 | } 629 | } 630 | }; 631 | 632 | test('is.undefined', t => { 633 | testType(t, 'undefined', ['nullOrUndefined']); 634 | }); 635 | 636 | test('is.null', t => { 637 | testType(t, 'null', ['nullOrUndefined']); 638 | }); 639 | 640 | test('is.string', t => { 641 | testType(t, 'string', ['emptyString', 'numericString']); 642 | }); 643 | 644 | test('is.number', t => { 645 | testType(t, 'number', ['integer', 'safeInteger', 'infinite']); 646 | }); 647 | 648 | test('is.positiveNumber', t => { 649 | t.true(is.positiveNumber(6)); 650 | t.true(is.positiveNumber(1.4)); 651 | t.true(is.positiveNumber(Number.POSITIVE_INFINITY)); 652 | 653 | t.notThrows(() => { 654 | assert.positiveNumber(6); 655 | }); 656 | t.notThrows(() => { 657 | assert.positiveNumber(1.4); 658 | }); 659 | t.notThrows(() => { 660 | assert.positiveNumber(Number.POSITIVE_INFINITY); 661 | }); 662 | 663 | t.false(is.positiveNumber(0)); 664 | t.false(is.positiveNumber(-0)); 665 | t.false(is.positiveNumber(-6)); 666 | t.false(is.positiveNumber(-1.4)); 667 | t.false(is.positiveNumber(Number.NEGATIVE_INFINITY)); 668 | 669 | t.throws(() => { 670 | assert.positiveNumber(0); 671 | }); 672 | t.throws(() => { 673 | assert.positiveNumber(-0); 674 | }); 675 | t.throws(() => { 676 | assert.positiveNumber(-6); 677 | }); 678 | t.throws(() => { 679 | assert.positiveNumber(-1.4); 680 | }); 681 | t.throws(() => { 682 | assert.positiveNumber(Number.NEGATIVE_INFINITY); 683 | }); 684 | }); 685 | 686 | test('is.negativeNumber', t => { 687 | t.true(is.negativeNumber(-6)); 688 | t.true(is.negativeNumber(-1.4)); 689 | t.true(is.negativeNumber(Number.NEGATIVE_INFINITY)); 690 | 691 | t.notThrows(() => { 692 | assert.negativeNumber(-6); 693 | }); 694 | t.notThrows(() => { 695 | assert.negativeNumber(-1.4); 696 | }); 697 | t.notThrows(() => { 698 | assert.negativeNumber(Number.NEGATIVE_INFINITY); 699 | }); 700 | 701 | t.false(is.negativeNumber(0)); 702 | t.false(is.negativeNumber(-0)); 703 | t.false(is.negativeNumber(6)); 704 | t.false(is.negativeNumber(1.4)); 705 | t.false(is.negativeNumber(Number.POSITIVE_INFINITY)); 706 | 707 | t.throws(() => { 708 | assert.negativeNumber(0); 709 | }); 710 | t.throws(() => { 711 | assert.negativeNumber(-0); 712 | }); 713 | t.throws(() => { 714 | assert.negativeNumber(6); 715 | }); 716 | t.throws(() => { 717 | assert.negativeNumber(1.4); 718 | }); 719 | t.throws(() => { 720 | assert.negativeNumber(Number.POSITIVE_INFINITY); 721 | }); 722 | }); 723 | 724 | test('is.bigint', t => { 725 | testType(t, 'bigint'); 726 | }); 727 | 728 | test('is.boolean', t => { 729 | testType(t, 'boolean'); 730 | }); 731 | 732 | test('is.symbol', t => { 733 | testType(t, 'symbol'); 734 | }); 735 | 736 | test('is.numericString', t => { 737 | testType(t, 'numericString'); 738 | t.false(is.numericString('')); 739 | t.false(is.numericString(' ')); 740 | t.false(is.numericString(' \t\t\n')); 741 | t.false(is.numericString(1)); 742 | t.throws(() => { 743 | assert.numericString(''); 744 | }); 745 | t.throws(() => { 746 | assert.numericString(1); 747 | }); 748 | }); 749 | 750 | test('is.array', t => { 751 | testType(t, 'array', ['emptyArray']); 752 | 753 | t.true(is.array([1, 2, 3], is.number)); 754 | t.false(is.array([1, '2', 3], is.number)); 755 | 756 | t.notThrows(() => { 757 | assert.array([1, 2], assert.number); 758 | }); 759 | 760 | t.throws(() => { 761 | assert.array([1, '2'], assert.number); 762 | }); 763 | 764 | t.notThrows(() => { 765 | const x: unknown[] = [1, 2, 3]; 766 | assert.array(x, assert.number); 767 | x[0]?.toFixed(0); 768 | }); 769 | 770 | t.notThrows(() => { 771 | const x: unknown[] = [1, 2, 3]; 772 | if (is.array(x, is.number)) { 773 | x[0]?.toFixed(0); 774 | } 775 | }); 776 | 777 | t.throws(() => { 778 | assert.array([1, '2'], assert.number, 'Expected numbers'); 779 | }, {message: /Expected numbers/}); 780 | }); 781 | 782 | test('is.function', t => { 783 | testType(t, 'function', ['generatorFunction', 'asyncGeneratorFunction', 'asyncFunction', 'boundFunction']); 784 | }); 785 | 786 | test('is.boundFunction', t => { 787 | t.false(is.boundFunction(function () {})); // eslint-disable-line prefer-arrow-callback 788 | 789 | t.throws(() => { 790 | assert.boundFunction(function () {}); // eslint-disable-line prefer-arrow-callback 791 | }); 792 | }); 793 | 794 | test('is.buffer', t => { 795 | testType(t, 'buffer'); 796 | }); 797 | 798 | test('is.blob', t => { 799 | testType(t, 'blob'); 800 | }); 801 | 802 | test('is.object', t => { 803 | const testData = types.get('object'); 804 | 805 | if (testData === undefined) { 806 | t.fail('is.object not defined'); 807 | 808 | return; 809 | } 810 | 811 | for (const element of testData.fixtures) { 812 | t.true(is.object(element)); 813 | t.notThrows(() => { 814 | assert.object(element); 815 | }); 816 | } 817 | }); 818 | 819 | test('is.regExp', t => { 820 | testType(t, 'regExp'); 821 | }); 822 | 823 | test('is.date', t => { 824 | testType(t, 'date'); 825 | }); 826 | 827 | test('is.error', t => { 828 | testType(t, 'error'); 829 | }); 830 | 831 | test('is.nativePromise', t => { 832 | testType(t, 'nativePromise'); 833 | }); 834 | 835 | test('is.promise', t => { 836 | testType(t, 'promise', ['nativePromise']); 837 | }); 838 | 839 | test('is.asyncFunction', t => { 840 | testType(t, 'asyncFunction', ['function']); 841 | 842 | const fixture = async () => {}; 843 | if (is.asyncFunction(fixture)) { 844 | t.true(is.function(fixture().then)); 845 | 846 | t.notThrows(() => { 847 | assert.function(fixture().then); 848 | }); 849 | } 850 | }); 851 | 852 | test('is.generator', t => { 853 | testType(t, 'generator'); 854 | }); 855 | 856 | test('is.asyncGenerator', t => { 857 | testType(t, 'asyncGenerator'); 858 | 859 | const fixture = (async function * () { 860 | yield 4; 861 | })(); 862 | if (is.asyncGenerator(fixture)) { 863 | t.true(is.function(fixture.next)); 864 | } 865 | }); 866 | 867 | test('is.generatorFunction', t => { 868 | testType(t, 'generatorFunction', ['function']); 869 | }); 870 | 871 | test('is.asyncGeneratorFunction', t => { 872 | testType(t, 'asyncGeneratorFunction', ['function']); 873 | 874 | const fixture = async function * () { 875 | yield 4; 876 | }; 877 | 878 | if (is.asyncGeneratorFunction(fixture)) { 879 | t.true(is.function(fixture().next)); 880 | } 881 | }); 882 | 883 | test('is.map', t => { 884 | testType(t, 'map', ['emptyMap']); 885 | }); 886 | 887 | test('is.set', t => { 888 | testType(t, 'set', ['emptySet']); 889 | }); 890 | 891 | test('is.weakMap', t => { 892 | testType(t, 'weakMap'); 893 | }); 894 | 895 | test('is.weakSet', t => { 896 | testType(t, 'weakSet'); 897 | }); 898 | 899 | test('is.weakRef', t => { 900 | testType(t, 'weakRef'); 901 | }); 902 | 903 | test('is.int8Array', t => { 904 | testType(t, 'int8Array'); 905 | }); 906 | 907 | test('is.uint8Array', t => { 908 | testType(t, 'uint8Array', ['buffer']); 909 | }); 910 | 911 | test('is.uint8ClampedArray', t => { 912 | testType(t, 'uint8ClampedArray'); 913 | }); 914 | 915 | test('is.int16Array', t => { 916 | testType(t, 'int16Array'); 917 | }); 918 | 919 | test('is.uint16Array', t => { 920 | testType(t, 'uint16Array'); 921 | }); 922 | 923 | test('is.int32Array', t => { 924 | testType(t, 'int32Array'); 925 | }); 926 | 927 | test('is.uint32Array', t => { 928 | testType(t, 'uint32Array'); 929 | }); 930 | 931 | test('is.float32Array', t => { 932 | testType(t, 'float32Array'); 933 | }); 934 | 935 | test('is.float64Array', t => { 936 | testType(t, 'float64Array'); 937 | }); 938 | 939 | test('is.bigInt64Array', t => { 940 | testType(t, 'bigInt64Array'); 941 | }); 942 | 943 | test('is.bigUint64Array', t => { 944 | testType(t, 'bigUint64Array'); 945 | }); 946 | 947 | test('is.arrayBuffer', t => { 948 | testType(t, 'arrayBuffer'); 949 | }); 950 | 951 | test('is.dataView', t => { 952 | testType(t, 'dataView'); 953 | }); 954 | 955 | test('is.enumCase', t => { 956 | enum NonNumericalEnum { 957 | Key1 = 'key1', 958 | Key2 = 'key2', 959 | } 960 | 961 | t.true(is.enumCase('key1', NonNumericalEnum)); 962 | t.notThrows(() => { 963 | assert.enumCase('key1', NonNumericalEnum); 964 | }); 965 | 966 | t.false(is.enumCase('invalid', NonNumericalEnum)); 967 | t.throws(() => { 968 | assert.enumCase('invalid', NonNumericalEnum); 969 | }); 970 | }); 971 | 972 | test('is.directInstanceOf', t => { 973 | const error = new Error('fixture'); 974 | const errorSubclass = new ErrorSubclassFixture(); 975 | 976 | t.true(is.directInstanceOf(error, Error)); 977 | t.true(is.directInstanceOf(errorSubclass, ErrorSubclassFixture)); 978 | t.notThrows(() => { 979 | assert.directInstanceOf(error, Error); 980 | }); 981 | t.notThrows(() => { 982 | assert.directInstanceOf(errorSubclass, ErrorSubclassFixture); 983 | }); 984 | 985 | t.false(is.directInstanceOf(error, ErrorSubclassFixture)); 986 | t.false(is.directInstanceOf(errorSubclass, Error)); 987 | t.throws(() => { 988 | assert.directInstanceOf(error, ErrorSubclassFixture); 989 | }); 990 | t.throws(() => { 991 | assert.directInstanceOf(errorSubclass, Error); 992 | }); 993 | 994 | t.false(is.directInstanceOf(undefined, Error)); 995 | t.false(is.directInstanceOf(null, Error)); 996 | }); 997 | 998 | test('is.urlInstance', t => { 999 | const url = new URL('https://example.com'); 1000 | t.true(is.urlInstance(url)); 1001 | t.false(is.urlInstance({})); 1002 | t.false(is.urlInstance(undefined)); 1003 | t.false(is.urlInstance(null)); 1004 | 1005 | t.notThrows(() => { 1006 | assert.urlInstance(url); 1007 | }); 1008 | t.throws(() => { 1009 | assert.urlInstance({}); 1010 | }); 1011 | t.throws(() => { 1012 | assert.urlInstance(undefined); 1013 | }); 1014 | t.throws(() => { 1015 | assert.urlInstance(null); 1016 | }); 1017 | }); 1018 | 1019 | test('is.urlString', t => { 1020 | const url = 'https://example.com'; 1021 | t.true(is.urlString(url)); 1022 | t.false(is.urlString(new URL(url))); 1023 | t.false(is.urlString({})); 1024 | t.false(is.urlString(undefined)); 1025 | t.false(is.urlString(null)); 1026 | 1027 | t.notThrows(() => { 1028 | assert.urlString(url); 1029 | }); 1030 | t.throws(() => { 1031 | assert.urlString(new URL(url)); 1032 | }); 1033 | t.throws(() => { 1034 | assert.urlString({}); 1035 | }); 1036 | t.throws(() => { 1037 | assert.urlString(undefined); 1038 | }); 1039 | t.throws(() => { 1040 | assert.urlString(null); 1041 | }); 1042 | }); 1043 | 1044 | test('is.truthy', t => { 1045 | t.true(is.truthy('unicorn')); 1046 | t.true(is.truthy('🦄')); 1047 | t.true(is.truthy(new Set())); 1048 | t.true(is.truthy(Symbol('🦄'))); 1049 | t.true(is.truthy(true)); 1050 | t.true(is.truthy(1)); 1051 | // Disabled until TS supports it for an ESnnnn target. 1052 | // t.true(is.truthy(1n)); 1053 | t.true(is.truthy(BigInt(1))); 1054 | 1055 | t.notThrows(() => { 1056 | assert.truthy('unicorn'); 1057 | }); 1058 | 1059 | t.notThrows(() => { 1060 | assert.truthy('🦄'); 1061 | }); 1062 | 1063 | t.notThrows(() => { 1064 | assert.truthy(new Set()); 1065 | }); 1066 | 1067 | t.notThrows(() => { 1068 | assert.truthy(Symbol('🦄')); 1069 | }); 1070 | 1071 | t.notThrows(() => { 1072 | assert.truthy(true); 1073 | }); 1074 | 1075 | t.notThrows(() => { 1076 | assert.truthy(1); 1077 | }); 1078 | 1079 | t.notThrows(() => { 1080 | assert.truthy(1n); 1081 | }); 1082 | 1083 | t.notThrows(() => { 1084 | assert.truthy(BigInt(1)); 1085 | }); 1086 | 1087 | // Checks that `assert.truthy` narrow downs boolean type to `true`. 1088 | { 1089 | const booleans = [true, false]; 1090 | const function_ = (value: true) => value; 1091 | assert.truthy(booleans[0]); 1092 | function_(booleans[0]); 1093 | } 1094 | 1095 | // Checks that `assert.truthy` excludes zero value from number type. 1096 | { 1097 | const bits: Array<0 | 1> = [1, 0, -0]; 1098 | const function_ = (value: 1) => value; 1099 | assert.truthy(bits[0]); 1100 | function_(bits[0]); 1101 | } 1102 | 1103 | // Checks that `assert.truthy` excludes zero value from bigint type. 1104 | { 1105 | const bits: Array<0n | 1n> = [1n, 0n, -0n]; 1106 | const function_ = (value: 1n) => value; 1107 | assert.truthy(bits[0]); 1108 | function_(bits[0]); 1109 | } 1110 | 1111 | // Checks that `assert.truthy` excludes empty string from string type. 1112 | { 1113 | const strings: Array<'nonEmpty' | ''> = ['nonEmpty', '']; 1114 | const function_ = (value: 'nonEmpty') => value; 1115 | assert.truthy(strings[0]); 1116 | function_(strings[0]); 1117 | } 1118 | 1119 | // Checks that `assert.truthy` excludes undefined from mixed type. 1120 | { 1121 | const maybeUndefineds = ['🦄', undefined]; 1122 | const function_ = (value: string) => value; 1123 | assert.truthy(maybeUndefineds[0]); 1124 | function_(maybeUndefineds[0]); 1125 | } 1126 | 1127 | // Checks that `assert.truthy` excludes null from mixed type. 1128 | { 1129 | const maybeNulls = ['🦄', null]; 1130 | const function_ = (value: string) => value; 1131 | assert.truthy(maybeNulls[0]); 1132 | function_(maybeNulls[0]); 1133 | } 1134 | }); 1135 | 1136 | test('is.falsy', t => { 1137 | t.true(is.falsy(false)); 1138 | t.true(is.falsy(0)); 1139 | t.true(is.falsy('')); 1140 | t.true(is.falsy(null)); 1141 | t.true(is.falsy(undefined)); 1142 | t.true(is.falsy(Number.NaN)); 1143 | t.true(is.falsy(0n)); 1144 | t.true(is.falsy(BigInt(0))); 1145 | 1146 | t.notThrows(() => { 1147 | assert.falsy(false); 1148 | }); 1149 | 1150 | t.notThrows(() => { 1151 | assert.falsy(0); 1152 | }); 1153 | 1154 | t.notThrows(() => { 1155 | assert.falsy(''); 1156 | }); 1157 | 1158 | t.notThrows(() => { 1159 | assert.falsy(null); 1160 | }); 1161 | 1162 | t.notThrows(() => { 1163 | assert.falsy(undefined); 1164 | }); 1165 | 1166 | t.notThrows(() => { 1167 | assert.falsy(Number.NaN); 1168 | }); 1169 | 1170 | t.notThrows(() => { 1171 | assert.falsy(0n); 1172 | }); 1173 | 1174 | t.notThrows(() => { 1175 | assert.falsy(BigInt(0)); 1176 | }); 1177 | 1178 | // Checks that `assert.falsy` narrow downs boolean type to `false`. 1179 | { 1180 | const booleans = [false, true]; 1181 | const function_ = (value?: false) => value; 1182 | assert.falsy(booleans[0]); 1183 | function_(booleans[0]); 1184 | } 1185 | 1186 | // Checks that `assert.falsy` narrow downs number type to `0`. 1187 | { 1188 | const bits = [0, -0, 1]; 1189 | const function_ = (value?: 0) => value; 1190 | assert.falsy(bits[0]); 1191 | function_(bits[0]); 1192 | assert.falsy(bits[1]); 1193 | function_(bits[1]); 1194 | } 1195 | 1196 | // Checks that `assert.falsy` narrow downs bigint type to `0n`. 1197 | { 1198 | const bits = [0n, -0n, 1n]; 1199 | const function_ = (value?: 0n) => value; 1200 | assert.falsy(bits[0]); 1201 | function_(bits[0]); 1202 | assert.falsy(bits[1]); 1203 | function_(bits[1]); 1204 | } 1205 | 1206 | // Checks that `assert.falsy` narrow downs string type to empty string. 1207 | { 1208 | const strings = ['', 'nonEmpty']; 1209 | const function_ = (value?: '') => value; 1210 | assert.falsy(strings[0]); 1211 | function_(strings[0]); 1212 | } 1213 | 1214 | // Checks that `assert.falsy` can narrow down mixed type to undefined. 1215 | { 1216 | const maybeUndefineds = [undefined, Symbol('🦄')]; 1217 | const function_ = (value: undefined) => value; 1218 | assert.falsy(maybeUndefineds[0]); 1219 | function_(maybeUndefineds[0]); 1220 | } 1221 | 1222 | // Checks that `assert.falsy` can narrow down mixed type to null. 1223 | { 1224 | const maybeNulls = [null, Symbol('🦄')]; 1225 | // eslint-disable-next-line @typescript-eslint/ban-types 1226 | const function_ = (value?: null) => value; 1227 | assert.falsy(maybeNulls[0]); 1228 | function_(maybeNulls[0]); 1229 | } 1230 | }); 1231 | 1232 | test('is.nan', t => { 1233 | testType(t, 'nan'); 1234 | }); 1235 | 1236 | test('is.nullOrUndefined', t => { 1237 | testType(t, 'nullOrUndefined', ['undefined', 'null']); 1238 | }); 1239 | 1240 | test('is.primitive', t => { 1241 | const primitives: Primitive[] = [ 1242 | undefined, 1243 | null, 1244 | '🦄', 1245 | 6, 1246 | Number.POSITIVE_INFINITY, 1247 | Number.NEGATIVE_INFINITY, 1248 | true, 1249 | false, 1250 | Symbol('🦄'), 1251 | // Disabled until TS supports it for an ESnnnn target. 1252 | // 6n 1253 | ]; 1254 | 1255 | for (const element of primitives) { 1256 | t.true(is.primitive(element)); 1257 | t.notThrows(() => { 1258 | assert.primitive(element); 1259 | }); 1260 | } 1261 | }); 1262 | 1263 | test('is.integer', t => { 1264 | testType(t, 'integer', ['number', 'safeInteger']); 1265 | t.false(is.integer(1.4)); 1266 | t.throws(() => { 1267 | assert.integer(1.4); 1268 | }); 1269 | }); 1270 | 1271 | test('is.safeInteger', t => { 1272 | testType(t, 'safeInteger', ['number', 'integer']); 1273 | t.false(is.safeInteger(2 ** 53)); 1274 | t.false(is.safeInteger(-(2 ** 53))); 1275 | t.throws(() => { 1276 | assert.safeInteger(2 ** 53); 1277 | }); 1278 | t.throws(() => { 1279 | assert.safeInteger(-(2 ** 53)); 1280 | }); 1281 | }); 1282 | 1283 | test('is.plainObject', t => { 1284 | testType(t, 'plainObject', ['object', 'promise']); 1285 | }); 1286 | 1287 | test('is.iterable', t => { 1288 | t.true(is.iterable('')); 1289 | t.true(is.iterable([])); 1290 | t.true(is.iterable(new Map())); 1291 | t.false(is.iterable(null)); 1292 | t.false(is.iterable(undefined)); 1293 | t.false(is.iterable(0)); 1294 | t.false(is.iterable(Number.NaN)); 1295 | t.false(is.iterable(Number.POSITIVE_INFINITY)); 1296 | t.false(is.iterable({})); 1297 | 1298 | t.notThrows(() => { 1299 | assert.iterable(''); 1300 | }); 1301 | t.notThrows(() => { 1302 | assert.iterable([]); 1303 | }); 1304 | t.notThrows(() => { 1305 | assert.iterable(new Map()); 1306 | }); 1307 | t.throws(() => { 1308 | assert.iterable(null); 1309 | }); 1310 | t.throws(() => { 1311 | assert.iterable(undefined); 1312 | }); 1313 | t.throws(() => { 1314 | assert.iterable(0); 1315 | }); 1316 | t.throws(() => { 1317 | assert.iterable(Number.NaN); 1318 | }); 1319 | t.throws(() => { 1320 | assert.iterable(Number.POSITIVE_INFINITY); 1321 | }); 1322 | t.throws(() => { 1323 | assert.iterable({}); 1324 | }); 1325 | }); 1326 | 1327 | test('is.asyncIterable', t => { 1328 | t.true(is.asyncIterable({ 1329 | [Symbol.asyncIterator]() {}, 1330 | })); 1331 | 1332 | t.false(is.asyncIterable(null)); 1333 | t.false(is.asyncIterable(undefined)); 1334 | t.false(is.asyncIterable(0)); 1335 | t.false(is.asyncIterable(Number.NaN)); 1336 | t.false(is.asyncIterable(Number.POSITIVE_INFINITY)); 1337 | t.false(is.asyncIterable({})); 1338 | 1339 | t.notThrows(() => { 1340 | assert.asyncIterable({ 1341 | [Symbol.asyncIterator]() {}, 1342 | }); 1343 | }); 1344 | 1345 | t.throws(() => { 1346 | assert.asyncIterable(null); 1347 | }); 1348 | t.throws(() => { 1349 | assert.asyncIterable(undefined); 1350 | }); 1351 | t.throws(() => { 1352 | assert.asyncIterable(0); 1353 | }); 1354 | t.throws(() => { 1355 | assert.asyncIterable(Number.NaN); 1356 | }); 1357 | t.throws(() => { 1358 | assert.asyncIterable(Number.POSITIVE_INFINITY); 1359 | }); 1360 | t.throws(() => { 1361 | assert.asyncIterable({}); 1362 | }); 1363 | }); 1364 | 1365 | test('is.class', t => { 1366 | class Foo {} // eslint-disable-line @typescript-eslint/no-extraneous-class 1367 | 1368 | const classDeclarations = [ 1369 | Foo, 1370 | class Bar extends Foo {}, 1371 | ]; 1372 | 1373 | for (const classDeclaration of classDeclarations) { 1374 | t.true(is.class(classDeclaration)); 1375 | 1376 | t.notThrows(() => { 1377 | assert.class(classDeclaration); 1378 | }); 1379 | } 1380 | }); 1381 | 1382 | test('is.typedArray', t => { 1383 | const typedArrays: TypedArray[] = [ 1384 | new Int8Array(), 1385 | new Uint8Array(), 1386 | new Uint8ClampedArray(), 1387 | new Uint16Array(), 1388 | new Int32Array(), 1389 | new Uint32Array(), 1390 | new Float32Array(), 1391 | new Float64Array(), 1392 | new BigInt64Array(), 1393 | new BigUint64Array(), 1394 | ]; 1395 | 1396 | for (const item of typedArrays) { 1397 | t.true(is.typedArray(item)); 1398 | 1399 | t.notThrows(() => { 1400 | assert.typedArray(item); 1401 | }); 1402 | } 1403 | 1404 | t.false(is.typedArray(new ArrayBuffer(1))); 1405 | t.false(is.typedArray([])); 1406 | t.false(is.typedArray({})); 1407 | 1408 | t.throws(() => { 1409 | assert.typedArray(new ArrayBuffer(1)); 1410 | }); 1411 | t.throws(() => { 1412 | assert.typedArray([]); 1413 | }); 1414 | t.throws(() => { 1415 | assert.typedArray({}); 1416 | }); 1417 | }); 1418 | 1419 | test('is.arrayLike', t => { 1420 | (function () { 1421 | t.true(is.arrayLike(arguments)); // eslint-disable-line prefer-rest-params 1422 | })(); 1423 | 1424 | t.true(is.arrayLike([])); 1425 | t.true(is.arrayLike('unicorn')); 1426 | 1427 | t.false(is.arrayLike({})); 1428 | t.false(is.arrayLike(() => {})); 1429 | t.false(is.arrayLike(new Map())); 1430 | 1431 | (function () { 1432 | t.notThrows(function () { 1433 | assert.arrayLike(arguments); // eslint-disable-line prefer-rest-params 1434 | }); 1435 | })(); 1436 | 1437 | t.notThrows(() => { 1438 | assert.arrayLike([]); 1439 | }); 1440 | t.notThrows(() => { 1441 | assert.arrayLike('unicorn'); 1442 | }); 1443 | 1444 | t.throws(() => { 1445 | assert.arrayLike({}); 1446 | }); 1447 | t.throws(() => { 1448 | assert.arrayLike(() => {}); 1449 | }); 1450 | t.throws(() => { 1451 | assert.arrayLike(new Map()); 1452 | }); 1453 | }); 1454 | 1455 | test('is.tupleLike', t => { 1456 | (function () { 1457 | t.false(is.tupleLike(arguments, [])); // eslint-disable-line prefer-rest-params 1458 | })(); 1459 | 1460 | t.true(is.tupleLike([], [])); 1461 | t.true(is.tupleLike([1, '2', true, {}, [], undefined, null], [is.number, is.string, is.boolean, is.object, is.array, is.undefined, is.nullOrUndefined])); 1462 | t.false(is.tupleLike('unicorn', [is.string])); 1463 | 1464 | t.false(is.tupleLike({}, [])); 1465 | t.false(is.tupleLike(() => {}, [is.function])); 1466 | t.false(is.tupleLike(new Map(), [is.map])); 1467 | 1468 | (function () { 1469 | t.throws(function () { 1470 | assert.tupleLike(arguments, []); // eslint-disable-line prefer-rest-params 1471 | }); 1472 | })(); 1473 | 1474 | t.notThrows(() => { 1475 | assert.tupleLike([], []); 1476 | }); 1477 | t.throws(() => { 1478 | assert.tupleLike('unicorn', [is.string]); 1479 | }); 1480 | 1481 | t.throws(() => { 1482 | assert.tupleLike({}, [is.object]); 1483 | }); 1484 | t.throws(() => { 1485 | assert.tupleLike(() => {}, [is.function]); 1486 | }); 1487 | t.throws(() => { 1488 | assert.tupleLike(new Map(), [is.map]); 1489 | }); 1490 | 1491 | { 1492 | const tuple = [[false, 'unicorn'], 'string', true]; 1493 | 1494 | if (is.tupleLike(tuple, [is.array, is.string, is.boolean])) { 1495 | if (is.tupleLike(tuple[0], [is.boolean, is.string])) { // eslint-disable-line unicorn/no-lonely-if 1496 | const value = tuple[0][1]; 1497 | expectTypeOf(value).toEqualTypeOf(); 1498 | } 1499 | } 1500 | } 1501 | 1502 | { 1503 | const tuple = [{isTest: true}, '1', true, null]; 1504 | 1505 | if (is.tupleLike(tuple, [is.nonEmptyObject, is.string, is.boolean, is.null])) { 1506 | const value = tuple[0]; 1507 | expectTypeOf(value).toEqualTypeOf>(); 1508 | } 1509 | } 1510 | 1511 | { 1512 | const tuple = [1, '1', true, null, undefined]; 1513 | 1514 | if (is.tupleLike(tuple, [is.number, is.string, is.boolean, is.undefined, is.null])) { 1515 | const numericValue = tuple[0]; 1516 | const stringValue = tuple[1]; 1517 | const booleanValue = tuple[2]; 1518 | const undefinedValue = tuple[3]; 1519 | const nullValue = tuple[4]; 1520 | expectTypeOf(numericValue).toEqualTypeOf(); 1521 | expectTypeOf(stringValue).toEqualTypeOf(); 1522 | expectTypeOf(booleanValue).toEqualTypeOf(); 1523 | expectTypeOf(undefinedValue).toEqualTypeOf(); 1524 | // eslint-disable-next-line @typescript-eslint/ban-types 1525 | expectTypeOf(nullValue).toEqualTypeOf(); 1526 | } 1527 | } 1528 | }); 1529 | 1530 | test('is.inRange', t => { 1531 | const x = 3; 1532 | 1533 | t.true(is.inRange(x, [0, 5])); 1534 | t.true(is.inRange(x, [5, 0])); 1535 | t.true(is.inRange(x, [-5, 5])); 1536 | t.true(is.inRange(x, [5, -5])); 1537 | t.false(is.inRange(x, [4, 8])); 1538 | t.true(is.inRange(-7, [-5, -10])); 1539 | t.true(is.inRange(-5, [-5, -10])); 1540 | t.true(is.inRange(-10, [-5, -10])); 1541 | 1542 | t.true(is.inRange(x, 10)); 1543 | t.true(is.inRange(0, 0)); 1544 | t.true(is.inRange(-2, -3)); 1545 | t.false(is.inRange(x, 2)); 1546 | t.false(is.inRange(-3, -2)); 1547 | 1548 | t.throws(() => { 1549 | // @ts-expect-error invalid argument 1550 | is.inRange(0, []); 1551 | }); 1552 | 1553 | t.throws(() => { 1554 | // @ts-expect-error invalid argument 1555 | is.inRange(0, [5]); 1556 | }); 1557 | 1558 | t.throws(() => { 1559 | // @ts-expect-error invalid argument 1560 | is.inRange(0, [1, 2, 3]); 1561 | }); 1562 | 1563 | t.notThrows(() => { 1564 | assert.inRange(x, [0, 5]); 1565 | }); 1566 | 1567 | t.notThrows(() => { 1568 | assert.inRange(x, [5, 0]); 1569 | }); 1570 | 1571 | t.notThrows(() => { 1572 | assert.inRange(x, [-5, 5]); 1573 | }); 1574 | 1575 | t.notThrows(() => { 1576 | assert.inRange(x, [5, -5]); 1577 | }); 1578 | 1579 | t.throws(() => { 1580 | assert.inRange(x, [4, 8]); 1581 | }); 1582 | 1583 | t.notThrows(() => { 1584 | assert.inRange(-7, [-5, -10]); 1585 | }); 1586 | 1587 | t.notThrows(() => { 1588 | assert.inRange(-5, [-5, -10]); 1589 | }); 1590 | 1591 | t.notThrows(() => { 1592 | assert.inRange(-10, [-5, -10]); 1593 | }); 1594 | 1595 | t.notThrows(() => { 1596 | assert.inRange(x, 10); 1597 | }); 1598 | 1599 | t.notThrows(() => { 1600 | assert.inRange(0, 0); 1601 | }); 1602 | 1603 | t.notThrows(() => { 1604 | assert.inRange(-2, -3); 1605 | }); 1606 | 1607 | t.throws(() => { 1608 | assert.inRange(x, 2); 1609 | }); 1610 | 1611 | t.throws(() => { 1612 | assert.inRange(-3, -2); 1613 | }); 1614 | 1615 | t.throws(() => { 1616 | // @ts-expect-error invalid argument 1617 | assert.inRange(0, []); 1618 | }); 1619 | 1620 | t.throws(() => { 1621 | // @ts-expect-error invalid argument 1622 | assert.inRange(0, [5]); 1623 | }); 1624 | 1625 | t.throws(() => { 1626 | // @ts-expect-error invalid argument 1627 | assert.inRange(0, [1, 2, 3]); 1628 | }); 1629 | }); 1630 | 1631 | test('is.htmlElement', t => { 1632 | testType(t, 'htmlElement'); 1633 | t.false(is.htmlElement({nodeType: 1, nodeName: 'div'})); 1634 | t.throws(() => { 1635 | assert.htmlElement({nodeType: 1, nodeName: 'div'}); 1636 | }); 1637 | 1638 | const tagNames = [ 1639 | 'div', 1640 | 'input', 1641 | 'span', 1642 | 'img', 1643 | 'canvas', 1644 | 'script', 1645 | ] as const; 1646 | 1647 | for (const tagName of tagNames) { 1648 | const element = document.createElement(tagName); 1649 | t.is(is(element), 'HTMLElement'); 1650 | } 1651 | }); 1652 | 1653 | test('is.observable', t => { 1654 | testType(t, 'observable'); 1655 | }); 1656 | 1657 | test('is.nodeStream', t => { 1658 | testType(t, 'nodeStream'); 1659 | }); 1660 | 1661 | test('is.infinite', t => { 1662 | testType(t, 'infinite', ['number']); 1663 | }); 1664 | 1665 | test('is.evenInteger', t => { 1666 | for (const element of [-6, 2, 4]) { 1667 | t.true(is.evenInteger(element)); 1668 | t.notThrows(() => { 1669 | assert.evenInteger(element); 1670 | }); 1671 | } 1672 | 1673 | for (const element of [-3, 1, 5]) { 1674 | t.false(is.evenInteger(element)); 1675 | t.throws(() => { 1676 | assert.evenInteger(element); 1677 | }); 1678 | } 1679 | }); 1680 | 1681 | test('is.oddInteger', t => { 1682 | for (const element of [-5, 7, 13]) { 1683 | t.true(is.oddInteger(element)); 1684 | t.notThrows(() => { 1685 | assert.oddInteger(element); 1686 | }); 1687 | } 1688 | 1689 | for (const element of [-8, 8, 10]) { 1690 | t.false(is.oddInteger(element)); 1691 | t.throws(() => { 1692 | assert.oddInteger(element); 1693 | }); 1694 | } 1695 | }); 1696 | 1697 | test('is.emptyArray', t => { 1698 | testType(t, 'emptyArray'); 1699 | }); 1700 | 1701 | test('is.nonEmptyArray', t => { 1702 | t.true(is.nonEmptyArray([1, 2, 3])); 1703 | t.false(is.nonEmptyArray([])); 1704 | t.false(is.nonEmptyArray(new Array())); // eslint-disable-line @typescript-eslint/no-array-constructor 1705 | 1706 | t.notThrows(() => { 1707 | assert.nonEmptyArray([1, 2, 3]); 1708 | }); 1709 | t.throws(() => { 1710 | assert.nonEmptyArray([]); 1711 | }); 1712 | t.throws(() => { 1713 | assert.nonEmptyArray(new Array()); // eslint-disable-line @typescript-eslint/no-array-constructor 1714 | }); 1715 | 1716 | { 1717 | const strings = ['🦄', 'unicorn'] as string[] | undefined; 1718 | const function_ = (value: string) => value; 1719 | 1720 | if (is.nonEmptyArray(strings)) { 1721 | const value = strings[0]; 1722 | function_(value); 1723 | } 1724 | } 1725 | 1726 | { 1727 | const mixed = ['🦄', 'unicorn', 1, 2]; 1728 | const function_ = (value: string | number) => value; 1729 | 1730 | if (is.nonEmptyArray(mixed)) { 1731 | const value = mixed[0]; 1732 | function_(value); 1733 | } 1734 | } 1735 | 1736 | { 1737 | const arrays = [['🦄'], ['unicorn']]; 1738 | const function_ = (value: string[]) => value; 1739 | 1740 | if (is.nonEmptyArray(arrays)) { 1741 | const value = arrays[0]; 1742 | function_(value); 1743 | } 1744 | } 1745 | 1746 | { 1747 | const strings = ['🦄', 'unicorn'] as string[] | undefined; 1748 | const function_ = (value: string) => value; 1749 | 1750 | assert.nonEmptyArray(strings); 1751 | 1752 | const value = strings[0]; 1753 | function_(value); 1754 | } 1755 | 1756 | { 1757 | const mixed = ['🦄', 'unicorn', 1, 2]; 1758 | const function_ = (value: string | number) => value; 1759 | 1760 | assert.nonEmptyArray(mixed); 1761 | 1762 | const value = mixed[0]; 1763 | function_(value); 1764 | } 1765 | 1766 | { 1767 | const arrays = [['🦄'], ['unicorn']]; 1768 | const function_ = (value: string[]) => value; 1769 | 1770 | assert.nonEmptyArray(arrays); 1771 | 1772 | const value = arrays[0]; 1773 | function_(value); 1774 | } 1775 | }); 1776 | 1777 | test('is.emptyString', t => { 1778 | testType(t, 'emptyString', ['string']); 1779 | t.false(is.emptyString('🦄')); 1780 | t.throws(() => { 1781 | assert.emptyString('🦄'); 1782 | }); 1783 | }); 1784 | 1785 | test('is.emptyStringOrWhitespace', t => { 1786 | testType(t, 'emptyString', ['string']); 1787 | t.true(is.emptyStringOrWhitespace(' ')); 1788 | t.false(is.emptyStringOrWhitespace('🦄')); 1789 | t.false(is.emptyStringOrWhitespace('unicorn')); 1790 | 1791 | t.notThrows(() => { 1792 | assert.emptyStringOrWhitespace(' '); 1793 | }); 1794 | t.throws(() => { 1795 | assert.emptyStringOrWhitespace('🦄'); 1796 | }); 1797 | t.throws(() => { 1798 | assert.emptyStringOrWhitespace('unicorn'); 1799 | }); 1800 | 1801 | let value = 'test'; // eslint-disable-line prefer-const -- can't use `const` here because then it will be inferred as `never` in the `if` block 1802 | if (is.emptyStringOrWhitespace(value)) { 1803 | value.charAt(0); // Should be inferred as `'' | Whitespace` and not `never` 1804 | } else { 1805 | value.charAt(0); // Should be inferred as `string` and not `never` 1806 | } 1807 | }); 1808 | 1809 | test('is.nonEmptyString', t => { 1810 | t.false(is.nonEmptyString('')); 1811 | t.false(is.nonEmptyString(String())); 1812 | t.true(is.nonEmptyString('🦄')); 1813 | 1814 | t.throws(() => { 1815 | assert.nonEmptyString(''); 1816 | }); 1817 | t.throws(() => { 1818 | assert.nonEmptyString(String()); 1819 | }); 1820 | t.notThrows(() => { 1821 | assert.nonEmptyString('🦄'); 1822 | }); 1823 | }); 1824 | 1825 | test('is.nonEmptyStringAndNotWhitespace', t => { 1826 | t.false(is.nonEmptyStringAndNotWhitespace(' ')); 1827 | t.true(is.nonEmptyStringAndNotWhitespace('🦄')); 1828 | 1829 | for (const value of [null, undefined, 5, Number.NaN, {}, []]) { 1830 | t.false(is.nonEmptyStringAndNotWhitespace(value)); 1831 | 1832 | t.throws(() => { 1833 | assert.nonEmptyStringAndNotWhitespace(value); 1834 | }); 1835 | } 1836 | 1837 | t.throws(() => { 1838 | assert.nonEmptyStringAndNotWhitespace(''); 1839 | }); 1840 | 1841 | t.notThrows(() => { 1842 | assert.nonEmptyStringAndNotWhitespace('🦄'); 1843 | }); 1844 | }); 1845 | 1846 | test('is.emptyObject', t => { 1847 | t.true(is.emptyObject({})); 1848 | t.true(is.emptyObject(new Object())); // eslint-disable-line no-object-constructor 1849 | t.false(is.emptyObject({unicorn: '🦄'})); 1850 | 1851 | t.notThrows(() => { 1852 | assert.emptyObject({}); 1853 | }); 1854 | t.notThrows(() => { 1855 | assert.emptyObject(new Object()); // eslint-disable-line no-object-constructor 1856 | }); 1857 | t.throws(() => { 1858 | assert.emptyObject({unicorn: '🦄'}); 1859 | }); 1860 | }); 1861 | 1862 | test('is.nonEmptyObject', t => { 1863 | const foo = {}; 1864 | is.nonEmptyObject(foo); 1865 | 1866 | t.false(is.nonEmptyObject({})); 1867 | t.false(is.nonEmptyObject(new Object())); // eslint-disable-line no-object-constructor 1868 | t.true(is.nonEmptyObject({unicorn: '🦄'})); 1869 | 1870 | t.throws(() => { 1871 | assert.nonEmptyObject({}); 1872 | }); 1873 | t.throws(() => { 1874 | assert.nonEmptyObject(new Object()); // eslint-disable-line no-object-constructor 1875 | }); 1876 | t.notThrows(() => { 1877 | assert.nonEmptyObject({unicorn: '🦄'}); 1878 | }); 1879 | }); 1880 | 1881 | test('is.emptySet', t => { 1882 | testType(t, 'emptySet'); 1883 | }); 1884 | 1885 | test('is.nonEmptySet', t => { 1886 | const temporarySet = new Set(); 1887 | t.false(is.nonEmptySet(temporarySet)); 1888 | t.throws(() => { 1889 | assert.nonEmptySet(temporarySet); 1890 | }); 1891 | 1892 | temporarySet.add(1); 1893 | t.true(is.nonEmptySet(temporarySet)); 1894 | t.notThrows(() => { 1895 | assert.nonEmptySet(temporarySet); 1896 | }); 1897 | }); 1898 | 1899 | test('is.emptyMap', t => { 1900 | testType(t, 'emptyMap'); 1901 | }); 1902 | 1903 | test('is.nonEmptyMap', t => { 1904 | const temporaryMap = new Map(); 1905 | t.false(is.nonEmptyMap(temporaryMap)); 1906 | t.throws(() => { 1907 | assert.nonEmptyMap(temporaryMap); 1908 | }); 1909 | 1910 | temporaryMap.set('unicorn', '🦄'); 1911 | t.true(is.nonEmptyMap(temporaryMap)); 1912 | t.notThrows(() => { 1913 | assert.nonEmptyMap(temporaryMap); 1914 | }); 1915 | }); 1916 | 1917 | test('is.propertyKey', t => { 1918 | t.true(is.propertyKey('key')); 1919 | t.true(is.propertyKey(42)); 1920 | t.true(is.propertyKey(Symbol(''))); 1921 | 1922 | t.false(is.propertyKey(null)); 1923 | t.false(is.propertyKey(undefined)); 1924 | t.false(is.propertyKey(true)); 1925 | t.false(is.propertyKey({})); 1926 | t.false(is.propertyKey([])); 1927 | t.false(is.propertyKey(new Map())); 1928 | t.false(is.propertyKey(new Set())); 1929 | }); 1930 | 1931 | test('is.any', t => { 1932 | t.true(is.any(is.string, {}, true, '🦄')); 1933 | t.true(is.any(is.object, false, {}, 'unicorns')); 1934 | t.false(is.any(is.boolean, '🦄', [], 3)); 1935 | t.false(is.any(is.integer, true, 'lol', {})); 1936 | t.true(is.any([is.string, is.number], {}, true, '🦄')); 1937 | t.false(is.any([is.boolean, is.number], 'unicorns', [], new Map())); 1938 | 1939 | t.throws(() => { 1940 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 1941 | is.any(null as any, true); 1942 | }); 1943 | 1944 | t.throws(() => { 1945 | is.any(is.string); 1946 | }); 1947 | 1948 | t.notThrows(() => { 1949 | assert.any(is.string, {}, true, '🦄'); 1950 | }); 1951 | 1952 | t.notThrows(() => { 1953 | assert.any(is.object, false, {}, 'unicorns'); 1954 | }); 1955 | 1956 | t.throws(() => { 1957 | assert.any(is.boolean, '🦄', [], 3); 1958 | }); 1959 | 1960 | t.throws(() => { 1961 | assert.any(is.integer, true, 'lol', {}); 1962 | }); 1963 | 1964 | t.throws(() => { 1965 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 1966 | assert.any(null as any, true); 1967 | }); 1968 | 1969 | t.throws(() => { 1970 | assert.any(is.string); 1971 | }); 1972 | 1973 | t.throws(() => { 1974 | assert.any(is.string, 1, 2, 3); 1975 | }, { 1976 | // Includes expected type and removes duplicates from received types: 1977 | message: /Expected values which are `string`. Received values of type `number`./, 1978 | }); 1979 | 1980 | t.throws(() => { 1981 | assert.any(is.string, 1, [4]); 1982 | }, { 1983 | // Includes expected type and lists all received types: 1984 | message: /Expected values which are `string`. Received values of types `number` and `Array`./, 1985 | }); 1986 | 1987 | t.throws(() => { 1988 | assert.any([is.string, is.nullOrUndefined], 1); 1989 | }, { 1990 | // Handles array as first argument: 1991 | message: /Expected values which are `string` or `null or undefined`. Received values of type `number`./, 1992 | }); 1993 | 1994 | t.throws(() => { 1995 | assert.any([is.string, is.number, is.boolean], null, undefined, Number.NaN); 1996 | }, { 1997 | // Handles more than 2 expected and received types: 1998 | message: /Expected values which are `string`, `number`, or `boolean`. Received values of types `null`, `undefined`, and `NaN`./, 1999 | }); 2000 | 2001 | t.throws(() => { 2002 | assert.any(() => false, 1); 2003 | }, { 2004 | // Default type assertion message 2005 | message: /Expected values which are `predicate returns truthy for any value`./, 2006 | }); 2007 | }); 2008 | 2009 | test('is.all', t => { 2010 | t.true(is.all(is.object, {}, new Set(), new Map())); 2011 | t.true(is.all(is.boolean, true, false)); 2012 | t.false(is.all(is.string, '🦄', [])); 2013 | t.false(is.all(is.set, new Map(), {})); 2014 | 2015 | t.true(is.all(is.array, ['1'], ['2'])); 2016 | 2017 | t.throws(() => { 2018 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 2019 | is.all(null as any, true); 2020 | }); 2021 | 2022 | t.throws(() => { 2023 | is.all(is.string); 2024 | }); 2025 | 2026 | t.notThrows(() => { 2027 | assert.all(is.object, {}, new Set(), new Map()); 2028 | }); 2029 | 2030 | t.notThrows(() => { 2031 | assert.all(is.boolean, true, false); 2032 | }); 2033 | 2034 | t.throws(() => { 2035 | assert.all(is.string, '🦄', []); 2036 | }); 2037 | 2038 | t.throws(() => { 2039 | assert.all(is.set, new Map(), {}); 2040 | }); 2041 | 2042 | t.throws(() => { 2043 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 2044 | assert.all(null as any, true); 2045 | }); 2046 | 2047 | t.throws(() => { 2048 | assert.all(is.string); 2049 | }); 2050 | 2051 | t.throws(() => { 2052 | assert.all(is.string, 1, 2, 3); 2053 | }, { 2054 | // Includes expected type and removes duplicates from received types: 2055 | message: /Expected values which are `string`. Received values of type `number`./, 2056 | }); 2057 | 2058 | t.throws(() => { 2059 | assert.all(is.string, 1, [4]); 2060 | }, { 2061 | // Includes expected type and lists all received types: 2062 | message: /Expected values which are `string`. Received values of types `number` and `Array`./, 2063 | }); 2064 | 2065 | t.throws(() => { 2066 | assert.all(() => false, 1); 2067 | }, { 2068 | // Default type assertion message 2069 | message: /Expected values which are `predicate returns truthy for all values`./, 2070 | }); 2071 | }); 2072 | 2073 | test('is.formData', t => { 2074 | const data = new window.FormData(); 2075 | t.true(is.formData(data)); 2076 | t.false(is.formData({})); 2077 | t.false(is.formData(undefined)); 2078 | t.false(is.formData(null)); 2079 | 2080 | t.notThrows(() => { 2081 | assert.formData(data); 2082 | }); 2083 | t.throws(() => { 2084 | assert.formData({}); 2085 | }); 2086 | t.throws(() => { 2087 | assert.formData(undefined); 2088 | }); 2089 | t.throws(() => { 2090 | assert.formData(null); 2091 | }); 2092 | }); 2093 | 2094 | test('is.urlSearchParams', t => { 2095 | const searchParameters = new URLSearchParams(); 2096 | t.true(is.urlSearchParams(searchParameters)); 2097 | t.false(is.urlSearchParams({})); 2098 | t.false(is.urlSearchParams(undefined)); 2099 | t.false(is.urlSearchParams(null)); 2100 | 2101 | t.notThrows(() => { 2102 | assert.urlSearchParams(searchParameters); 2103 | }); 2104 | t.throws(() => { 2105 | assert.urlSearchParams({}); 2106 | }); 2107 | t.throws(() => { 2108 | assert.urlSearchParams(undefined); 2109 | }); 2110 | t.throws(() => { 2111 | assert.urlSearchParams(null); 2112 | }); 2113 | }); 2114 | 2115 | test('is.validDate', t => { 2116 | t.true(is.validDate(new Date())); 2117 | t.false(is.validDate(new Date('x'))); 2118 | t.notThrows(() => { 2119 | assert.validDate(new Date()); 2120 | }); 2121 | t.throws(() => { 2122 | assert.validDate(new Date('x')); 2123 | }); 2124 | }); 2125 | 2126 | test('is.validLength', t => { 2127 | t.true(is.validLength(1)); 2128 | t.true(is.validLength(0)); 2129 | t.false(is.validLength(-1)); 2130 | t.false(is.validLength(0.1)); 2131 | t.notThrows(() => { 2132 | assert.validLength(1); 2133 | }); 2134 | t.throws(() => { 2135 | assert.validLength(-1); 2136 | }); 2137 | }); 2138 | 2139 | test('is.whitespaceString', t => { 2140 | t.true(is.whitespaceString(' ')); 2141 | t.true(is.whitespaceString(' ')); 2142 | t.true(is.whitespaceString('   ')); 2143 | t.true(is.whitespaceString('\u3000')); 2144 | t.true(is.whitespaceString(' ')); 2145 | t.false(is.whitespaceString('')); 2146 | t.false(is.whitespaceString('-')); 2147 | t.false(is.whitespaceString(' hi ')); 2148 | }); 2149 | 2150 | test('assert', t => { 2151 | // Contrived test showing that TypeScript acknowledges the type assertion in `assert.number()`. 2152 | // Real--world usage includes asserting user input, but here we use a random number/string generator. 2153 | t.plan(2); 2154 | 2155 | const getNumberOrStringRandomly = (): number | string => { 2156 | const random = Math.random(); 2157 | 2158 | if (random < 0.5) { 2159 | return 'sometimes this function returns text'; 2160 | } 2161 | 2162 | return random; 2163 | }; 2164 | 2165 | const canUseOnlyNumber = (badlyTypedArgument: any): number => { 2166 | // Narrow the type to number, or throw an error at runtime for non-numbers. 2167 | assert.number(badlyTypedArgument); 2168 | 2169 | // Both the type and runtime value is number. 2170 | return 1000 * badlyTypedArgument; 2171 | }; 2172 | 2173 | const badlyTypedVariable: any = getNumberOrStringRandomly(); 2174 | 2175 | t.true(is.number(badlyTypedVariable) || is.string(badlyTypedVariable)); 2176 | 2177 | // Using try/catch for test purposes only. 2178 | try { 2179 | const result = canUseOnlyNumber(badlyTypedVariable); 2180 | 2181 | // Got lucky, the input was a number yielding a good result. 2182 | t.true(is.number(result)); 2183 | } catch { 2184 | // Assertion was tripped. 2185 | t.true(is.string(badlyTypedVariable)); 2186 | } 2187 | }); 2188 | 2189 | test('custom assertion message', t => { 2190 | const message = 'Custom error message'; 2191 | 2192 | t.throws(() => { 2193 | assert.array(undefined, undefined, message); 2194 | }, {instanceOf: TypeError, message}); 2195 | 2196 | t.throws(() => { 2197 | assert.arrayBuffer(undefined, message); 2198 | }, {instanceOf: TypeError, message}); 2199 | 2200 | t.throws(() => { 2201 | assert.arrayLike(undefined, message); 2202 | }, {instanceOf: TypeError, message}); 2203 | 2204 | t.throws(() => { 2205 | assert.asyncFunction(undefined, message); 2206 | }, {instanceOf: TypeError, message}); 2207 | 2208 | t.throws(() => { 2209 | assert.asyncGenerator(undefined, message); 2210 | }, {instanceOf: TypeError, message}); 2211 | 2212 | t.throws(() => { 2213 | assert.asyncGeneratorFunction(undefined, message); 2214 | }, {instanceOf: TypeError, message}); 2215 | 2216 | t.throws(() => { 2217 | assert.asyncIterable(undefined, message); 2218 | }, {instanceOf: TypeError, message}); 2219 | 2220 | t.throws(() => { 2221 | assert.bigInt64Array(undefined, message); 2222 | }, {instanceOf: TypeError, message}); 2223 | 2224 | t.throws(() => { 2225 | assert.bigUint64Array(undefined, message); 2226 | }, {instanceOf: TypeError, message}); 2227 | 2228 | t.throws(() => { 2229 | assert.bigint(undefined, message); 2230 | }, {instanceOf: TypeError, message}); 2231 | 2232 | t.throws(() => { 2233 | assert.blob(undefined, message); 2234 | }, {instanceOf: TypeError, message}); 2235 | 2236 | t.throws(() => { 2237 | assert.boolean(undefined, message); 2238 | }, {instanceOf: TypeError, message}); 2239 | 2240 | t.throws(() => { 2241 | assert.boundFunction(undefined, message); 2242 | }, {instanceOf: TypeError, message}); 2243 | 2244 | t.throws(() => { 2245 | assert.buffer(undefined, message); 2246 | }, {instanceOf: TypeError, message}); 2247 | 2248 | t.throws(() => { 2249 | assert.class(undefined, message); 2250 | }, {instanceOf: TypeError, message}); 2251 | 2252 | t.throws(() => { 2253 | assert.dataView(undefined, message); 2254 | }, {instanceOf: TypeError, message}); 2255 | 2256 | t.throws(() => { 2257 | assert.date(undefined, message); 2258 | }, {instanceOf: TypeError, message}); 2259 | 2260 | t.throws(() => { 2261 | assert.directInstanceOf(undefined, Error, message); 2262 | }, {instanceOf: TypeError, message}); 2263 | 2264 | t.throws(() => { 2265 | assert.emptyArray(undefined, message); 2266 | }, {instanceOf: TypeError, message}); 2267 | 2268 | t.throws(() => { 2269 | assert.emptyMap(undefined, message); 2270 | }, {instanceOf: TypeError, message}); 2271 | 2272 | t.throws(() => { 2273 | assert.emptyObject(undefined, message); 2274 | }, {instanceOf: TypeError, message}); 2275 | 2276 | t.throws(() => { 2277 | assert.emptySet(undefined, message); 2278 | }, {instanceOf: TypeError, message}); 2279 | 2280 | t.throws(() => { 2281 | assert.emptyString(undefined, message); 2282 | }, {instanceOf: TypeError, message}); 2283 | 2284 | t.throws(() => { 2285 | assert.emptyStringOrWhitespace(undefined, message); 2286 | }, {instanceOf: TypeError, message}); 2287 | 2288 | t.throws(() => { 2289 | enum Enum {} 2290 | assert.enumCase('invalid', Enum, message); 2291 | }, {instanceOf: TypeError, message}); 2292 | 2293 | t.throws(() => { 2294 | assert.error(undefined, message); 2295 | }, {instanceOf: TypeError, message}); 2296 | 2297 | t.throws(() => { 2298 | assert.evenInteger(33, message); 2299 | }, {instanceOf: TypeError, message}); 2300 | 2301 | t.throws(() => { 2302 | assert.falsy(true, message); 2303 | }, {instanceOf: TypeError, message}); 2304 | 2305 | t.throws(() => { 2306 | assert.float32Array(undefined, message); 2307 | }, {instanceOf: TypeError, message}); 2308 | 2309 | t.throws(() => { 2310 | assert.float64Array(undefined, message); 2311 | }, {instanceOf: TypeError, message}); 2312 | 2313 | t.throws(() => { 2314 | assert.formData(undefined, message); 2315 | }, {instanceOf: TypeError, message}); 2316 | 2317 | t.throws(() => { 2318 | assert.function(undefined, message); 2319 | }, {instanceOf: TypeError, message}); 2320 | 2321 | t.throws(() => { 2322 | assert.generator(undefined, message); 2323 | }, {instanceOf: TypeError, message}); 2324 | 2325 | t.throws(() => { 2326 | assert.generatorFunction(undefined, message); 2327 | }, {instanceOf: TypeError, message}); 2328 | 2329 | t.throws(() => { 2330 | assert.htmlElement(undefined, message); 2331 | }, {instanceOf: TypeError, message}); 2332 | 2333 | t.throws(() => { 2334 | assert.inRange(5, [1, 2], message); 2335 | }, {instanceOf: TypeError, message}); 2336 | 2337 | t.throws(() => { 2338 | assert.infinite(undefined, message); 2339 | }, {instanceOf: TypeError, message}); 2340 | 2341 | t.throws(() => { 2342 | assert.int16Array(undefined, message); 2343 | }, {instanceOf: TypeError, message}); 2344 | 2345 | t.throws(() => { 2346 | assert.int32Array(undefined, message); 2347 | }, {instanceOf: TypeError, message}); 2348 | 2349 | t.throws(() => { 2350 | assert.int8Array(undefined, message); 2351 | }, {instanceOf: TypeError, message}); 2352 | 2353 | t.throws(() => { 2354 | assert.integer(undefined, message); 2355 | }, {instanceOf: TypeError, message}); 2356 | 2357 | t.throws(() => { 2358 | assert.iterable(undefined, message); 2359 | }, {instanceOf: TypeError, message}); 2360 | 2361 | t.throws(() => { 2362 | assert.map(undefined, message); 2363 | }, {instanceOf: TypeError, message}); 2364 | 2365 | t.throws(() => { 2366 | assert.nan(undefined, message); 2367 | }, {instanceOf: TypeError, message}); 2368 | 2369 | t.throws(() => { 2370 | assert.nativePromise(undefined, message); 2371 | }, {instanceOf: TypeError, message}); 2372 | 2373 | t.throws(() => { 2374 | assert.negativeNumber(undefined, message); 2375 | }, {instanceOf: TypeError, message}); 2376 | 2377 | t.throws(() => { 2378 | assert.nodeStream(undefined, message); 2379 | }, {instanceOf: TypeError, message}); 2380 | 2381 | t.throws(() => { 2382 | assert.nonEmptyArray(undefined, message); 2383 | }, {instanceOf: TypeError, message}); 2384 | 2385 | t.throws(() => { 2386 | assert.nonEmptyMap(undefined, message); 2387 | }, {instanceOf: TypeError, message}); 2388 | 2389 | t.throws(() => { 2390 | assert.nonEmptyObject(undefined, message); 2391 | }, {instanceOf: TypeError, message}); 2392 | 2393 | t.throws(() => { 2394 | assert.nonEmptySet(undefined, message); 2395 | }, {instanceOf: TypeError, message}); 2396 | 2397 | t.throws(() => { 2398 | assert.nonEmptyString(undefined, message); 2399 | }, {instanceOf: TypeError, message}); 2400 | 2401 | t.throws(() => { 2402 | assert.nonEmptyStringAndNotWhitespace(undefined, message); 2403 | }, {instanceOf: TypeError, message}); 2404 | 2405 | t.throws(() => { 2406 | assert.null(undefined, message); 2407 | }, {instanceOf: TypeError, message}); 2408 | 2409 | t.throws(() => { 2410 | assert.nullOrUndefined(false, message); 2411 | }, {instanceOf: TypeError, message}); 2412 | 2413 | t.throws(() => { 2414 | assert.number(undefined, message); 2415 | }, {instanceOf: TypeError, message}); 2416 | 2417 | t.throws(() => { 2418 | assert.numericString(undefined, message); 2419 | }, {instanceOf: TypeError, message}); 2420 | 2421 | t.throws(() => { 2422 | assert.object(undefined, message); 2423 | }, {instanceOf: TypeError, message}); 2424 | 2425 | t.throws(() => { 2426 | assert.observable(undefined, message); 2427 | }, {instanceOf: TypeError, message}); 2428 | 2429 | t.throws(() => { 2430 | assert.oddInteger(42, message); 2431 | }, {instanceOf: TypeError, message}); 2432 | 2433 | t.throws(() => { 2434 | assert.plainObject(undefined, message); 2435 | }, {instanceOf: TypeError, message}); 2436 | 2437 | t.throws(() => { 2438 | assert.positiveNumber(undefined, message); 2439 | }, {instanceOf: TypeError, message}); 2440 | 2441 | t.throws(() => { 2442 | assert.primitive([], message); 2443 | }, {instanceOf: TypeError, message}); 2444 | 2445 | t.throws(() => { 2446 | assert.promise(undefined, message); 2447 | }, {instanceOf: TypeError, message}); 2448 | 2449 | t.throws(() => { 2450 | assert.propertyKey(undefined, message); 2451 | }, {instanceOf: TypeError, message}); 2452 | 2453 | t.throws(() => { 2454 | assert.regExp(undefined, message); 2455 | }, {instanceOf: TypeError, message}); 2456 | 2457 | t.throws(() => { 2458 | assert.safeInteger(undefined, message); 2459 | }, {instanceOf: TypeError, message}); 2460 | 2461 | t.throws(() => { 2462 | assert.set(undefined, message); 2463 | }, {instanceOf: TypeError, message}); 2464 | 2465 | t.throws(() => { 2466 | assert.sharedArrayBuffer(undefined, message); 2467 | }, {instanceOf: TypeError, message}); 2468 | 2469 | t.throws(() => { 2470 | assert.string(undefined, message); 2471 | }, {instanceOf: TypeError, message}); 2472 | 2473 | t.throws(() => { 2474 | assert.symbol(undefined, message); 2475 | }, {instanceOf: TypeError, message}); 2476 | 2477 | t.throws(() => { 2478 | assert.truthy(undefined, message); 2479 | }, {instanceOf: TypeError, message}); 2480 | 2481 | t.throws(() => { 2482 | assert.tupleLike(undefined, [], message); 2483 | }, {instanceOf: TypeError, message}); 2484 | 2485 | t.throws(() => { 2486 | assert.typedArray(undefined, message); 2487 | }, {instanceOf: TypeError, message}); 2488 | 2489 | t.throws(() => { 2490 | assert.uint16Array(undefined, message); 2491 | }, {instanceOf: TypeError, message}); 2492 | 2493 | t.throws(() => { 2494 | assert.uint32Array(undefined, message); 2495 | }, {instanceOf: TypeError, message}); 2496 | 2497 | t.throws(() => { 2498 | assert.uint8Array(undefined, message); 2499 | }, {instanceOf: TypeError, message}); 2500 | 2501 | t.throws(() => { 2502 | assert.uint8ClampedArray(undefined, message); 2503 | }, {instanceOf: TypeError, message}); 2504 | 2505 | t.throws(() => { 2506 | assert.undefined(false, message); 2507 | }, {instanceOf: TypeError, message}); 2508 | 2509 | t.throws(() => { 2510 | assert.urlInstance(undefined, message); 2511 | }, {instanceOf: TypeError, message}); 2512 | 2513 | t.throws(() => { 2514 | assert.urlSearchParams(undefined, message); 2515 | }, {instanceOf: TypeError, message}); 2516 | 2517 | t.throws(() => { 2518 | assert.urlString(undefined, message); 2519 | }, {instanceOf: TypeError, message}); 2520 | 2521 | t.throws(() => { 2522 | assert.validDate(undefined, message); 2523 | }, {instanceOf: TypeError, message}); 2524 | 2525 | t.throws(() => { 2526 | assert.validLength(undefined, message); 2527 | }, {instanceOf: TypeError, message}); 2528 | 2529 | t.throws(() => { 2530 | assert.weakMap(undefined, message); 2531 | }, {instanceOf: TypeError, message}); 2532 | 2533 | t.throws(() => { 2534 | assert.weakRef(undefined, message); 2535 | }, {instanceOf: TypeError, message}); 2536 | 2537 | t.throws(() => { 2538 | assert.weakSet(undefined, message); 2539 | }, {instanceOf: TypeError, message}); 2540 | 2541 | t.throws(() => { 2542 | assert.whitespaceString(undefined, message); 2543 | }, {instanceOf: TypeError, message}); 2544 | }); 2545 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@sindresorhus/tsconfig", 3 | "include": [ 4 | "source" 5 | ], 6 | } 7 | --------------------------------------------------------------------------------