Compare commits

...

245 commits
v0.2.0 ... main

Author SHA1 Message Date
Sindre Sorhus
7821031c66 Fix CI 2026-05-11 22:57:22 +09:00
Sindre Sorhus
a439305554 8.1.0 2026-05-11 20:22:19 +09:00
Sindre Sorhus
2d4956e634 Add negative assertion helper
Fixes #220
2026-05-11 20:17:16 +09:00
Sindre Sorhus
48df5c429c 8.0.0 2026-04-09 22:09:01 +07:00
Sindre Sorhus
13febb6b01 Fix some type guards 2026-04-09 14:56:49 +07:00
Sindre Sorhus
cb4ee0e92c Fix isEnumCase incorrectly accepting numeric enum key names 2026-04-09 14:17:12 +07:00
Sindre Sorhus
54fc09406a Add negativeInteger, nonNegativeInteger, arrayOf, and oneOf predicates 2026-04-08 19:13:51 +07:00
Sindre Sorhus
63be5c0c19 Add finiteNumber, nonNegativeNumber, and positiveInteger predicates 2026-04-08 16:26:44 +07:00
Sindre Sorhus
ac46b5400d Fix isInRange silently returning false when range contains NaN 2026-04-08 15:09:53 +07:00
Sindre Sorhus
47415dc46a Fix isNumericString incorrectly accepting strings with surrounding whitespace 2026-04-08 05:51:14 +07:00
Sindre Sorhus
3b40955b02 Fix handling of functions and arrays in isEmptyObject and isNonEmptyObject 2026-04-08 05:51:13 +07:00
Sindre Sorhus
faf700367e Require Node.js 22 2026-04-08 04:38:52 +07:00
Sindre Sorhus
eff8e6b318 7.2.0 2025-12-27 11:35:17 +01:00
Sindre Sorhus
9bdcd9b57f Add predicate factory mode to is.any and is.all
Fixes #218
2025-12-27 11:33:25 +01:00
Sindre Sorhus
fbcc68e139 7.1.1 2025-11-01 00:20:45 +07:00
Tim Griesser
e7c84fcb79
Fix is.class for minified class expression (#217) 2025-11-01 00:18:25 +07:00
Sindre Sorhus
d22ab62991 7.1.0 2025-09-14 02:05:33 +07:00
Sindre Sorhus
1f2440ae0d Add is.optional and assert.optional
Fixes #111
2025-09-13 15:48:57 +07:00
Sindre Sorhus
c68ad76062 Fix TypeScript type narrowing issue with isUrlString
Fixes #212
2025-09-12 05:08:52 +07:00
Bjorn Stromberg
ef35cc350a
Structure fixtures so they can be easily tested for exclusivity (#215) 2025-06-06 13:58:46 +02:00
Sindre Sorhus
882a91c54f 7.0.2 2025-06-04 12:57:42 +03:00
Sindre Sorhus
e8e8124ba7 FIx observable checking
Fixes #214
2025-06-04 12:55:44 +03:00
Sindre Sorhus
47a5099325 Minor tweaks 2025-06-04 12:12:42 +03:00
Sindre Sorhus
e0976457e0 7.0.1 2024-09-06 22:54:53 +07:00
Martin Eneqvist
5565c5e3ba
Fix passing in assertion message to assertArray (#210)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2024-09-06 22:52:56 +07:00
Sindre Sorhus
ab85d9bca9 7.0.0 2024-07-10 15:43:01 +02:00
Sindre Sorhus
0ff273fee8 Require Node.js 18 2024-07-10 15:41:12 +02:00
Martin Eneqvist
25a376875d
Fix type guard for isWhitespaceString and isEmptyStringOrWhitespace (#207) 2024-06-26 14:31:56 +02:00
Bjorn Stromberg
8cbcaee674
Remove deprecated methods and improve Class definition (#209) 2024-06-26 14:30:00 +02:00
Bjorn Stromberg
92699e1049
Replace ts-node with tsimp (#208) 2024-06-25 02:08:48 +02:00
Sindre Sorhus
47f49741ea 6.3.1 2024-05-16 11:15:23 +03:00
Sindre Sorhus
0df21e4151 Add missing type guard for is.enumCase
Fixes #205
2024-05-16 11:11:44 +03:00
Sindre Sorhus
f7148e19dc Meta tweaks 2024-04-29 01:32:06 +07:00
Sindre Sorhus
a1987f8bad 6.3.0 2024-04-23 12:59:46 +07:00
Martin Eneqvist
f2e5834421
Support custom assertion messages (#204)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2024-04-23 12:58:28 +07:00
Sindre Sorhus
664b9077e1 6.2.0 2024-02-29 14:29:43 +07:00
Sindre Sorhus
07ea404e86 Meta tweaks 2024-02-29 14:26:01 +07:00
Martin Eneqvist
e9418fe1b9
Add .validDate() (#203) 2024-02-29 14:23:30 +07:00
patrik csak
0e687a23a8
Fix readme headings (#202) 2024-01-06 14:30:28 +07:00
Sindre Sorhus
1acbd9e202 6.1.0 2023-10-26 21:39:39 +07:00
Simon Podlipsky
0d4cf6fcc8
Improve TypeScript type for isNonEmptyString() and isNonEmptyStringAndNotWhitespace() (#200) 2023-10-26 21:37:39 +07:00
Sindre Sorhus
f10e2caf3d 6.0.1 2023-10-15 19:26:47 +07:00
Sindre Sorhus
e7e2213e91 directInstanceOf: Fix handling of undefined and null
Fixes #199
2023-10-15 16:01:29 +07:00
Bjorn Stromberg
9d6c91ee58
Add Node.js 20 to CI (#181) 2023-08-16 12:09:57 +02:00
Sindre Sorhus
877ed1cc6a 6.0.0 2023-08-15 20:51:44 +02:00
Sindre Sorhus
dadca59f6a Update dev dependencies 2023-08-15 20:50:56 +02:00
Bjorn Stromberg
68e0c95857
Update @sindresorhus/tsconfig to v4 (#194) 2023-08-10 16:07:56 +02:00
Bjorn Stromberg
bcec30d735
Rename is.domElement() to is.htmlElement() (#196) 2023-08-10 16:06:46 +02:00
Bjorn Stromberg
ee79af32b6
Update class method description (#195)
Co-authored-by: Harminder Virk <virk.officials@gmail.com>
2023-08-10 16:05:22 +02:00
Bjorn Stromberg
85c89925b6
Give better assertion messages for assert.all and assert.any (#193) 2023-08-09 13:49:06 +02:00
Bjorn Stromberg
e03c249d6c
Drop support for Node.js 14 (#192) 2023-08-07 17:18:36 +02:00
Bjorn Stromberg
5044c91273
Implement named exports (#191) 2023-08-07 02:50:03 +02:00
Bjorn Stromberg
bd5dfda993
Replace enums with string literals (#190) 2023-07-30 13:32:34 +02:00
Sindre Sorhus
44beb083a3 5.6.0 2023-07-23 14:40:00 +02:00
Tal Michel
3868f47783
Add .tupleLike() (#189)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2023-07-23 14:35:23 +02:00
Sindre Sorhus
94dc715577 5.5.2 2023-07-17 11:42:55 +02:00
Eugene
20ad8231c2
Fix is.nonEmptyArray() type narrowing with undefined (#188) 2023-07-17 11:42:04 +02:00
Sindre Sorhus
ad0c3b1429 5.5.1 2023-07-16 16:20:29 +02:00
hyperbola
9d26c020ee
Fix type guards for assert.{truthy,falsy,nan} (#187) 2023-07-16 16:19:31 +02:00
Sindre Sorhus
278e0e9696 5.5.0 2023-07-15 00:28:14 +02:00
Eugene
1284da085f
Add is.positiveNumber and is.negativeNumber (#184) 2023-07-15 00:26:30 +02:00
Eugene
3177d11801
Fix type narrowing for nonEmptyArray (#185) 2023-07-15 00:24:56 +02:00
Sindre Sorhus
9265e9072d Add test for #183 2023-06-10 11:43:41 +03:00
Sindre Sorhus
7d468191f4 5.4.1 2023-06-04 11:04:07 +03:00
Bjorn Stromberg
d1574d358d
Revert exports change in package.json (#180) 2023-06-04 11:01:35 +03:00
Sindre Sorhus
61a437eba3 5.4.0 2023-05-30 21:16:59 +07:00
Sindre Sorhus
65404fbd8e Meta tweaks 2023-05-30 21:15:24 +07:00
Xananax
888e145c5a
Improve type guard/assertion of numericString() (#178) 2023-05-30 18:43:51 +07:00
Sindre Sorhus
e559b37b72 Update dev dependencies 2022-10-17 18:19:38 +07:00
Sindre Sorhus
f3693674f6 Add failing test for #174 2022-10-17 17:51:49 +07:00
Sindre Sorhus
911f44dc36 5.3.0 2022-07-21 16:30:26 +02:00
Sindre Sorhus
33cd815503 Meta tweaks 2022-07-21 16:28:44 +02:00
Sindre Sorhus
592d9093cd Make nonEmptyArray() more strongly-typed
Fixes #171
2022-07-21 16:28:43 +02:00
Sindre Sorhus
d3ff1fdfce 5.2.0 2022-06-21 14:07:38 +02:00
ehmicky
45cae31f4d
Improve plainObject() (#169) 2022-06-21 14:05:40 +02:00
Sindre Sorhus
dc99f7cd4a 5.1.0 2022-06-13 14:07:07 +07:00
Eric(书生)
e503a9ec49
Add .weakRef() (#165)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2022-06-13 14:05:26 +07:00
Sindre Sorhus
06d217f70c 5.0.1 2022-06-11 18:28:13 +07:00
Sindre Sorhus
ac7c567c2b Fix typo 2022-06-11 18:27:36 +07:00
Sindre Sorhus
778c5da5b3 5.0.0 2022-06-11 18:19:55 +07:00
Sindre Sorhus
d6fc1ce0fe Require Node.js 14, TS 4.7, and move to ESM (#167) 2022-06-11 17:44:43 +07:00
Filip Skokan
c408f5a268
Fix NaN detection in .is() (#159) 2022-06-10 00:05:31 +07:00
Sindre Sorhus
65ea91297e 4.6.0 2022-02-27 14:21:30 +07:00
Eric(书生)
5b7ea154e6
Add .isBlob() (#162)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2022-02-27 14:16:25 +07:00
Sindre Sorhus
6cbefb9af7 Meta tweaks 2022-02-25 16:19:29 +07:00
Sindre Sorhus
dc2dc9a438 4.5.0 2022-02-25 16:16:30 +07:00
Ivan Katliarchuk
23cf074a73
Add .nonEmptyStringAndNotWhitespace() (#161)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2022-02-25 16:10:57 +07:00
Sindre Sorhus
04ccf21dba Document TypeScript naming limitation
Fixes #157
2022-02-01 11:37:28 +07:00
Sindre Sorhus
c3d12667fd 4.4.0 2022-01-25 17:29:45 +07:00
Zane Shannon
63d75d68ee
Add type guard for is.truthy and is.falsy (#151) 2022-01-25 17:28:33 +07:00
Pedro Augusto de Paula Barbosa
73daee6648
Improve .enumCase doc formatting in readme (#154) 2022-01-18 11:48:03 +07:00
Sindre Sorhus
b1efe7f5cf 4.3.0 2022-01-17 13:04:39 +07:00
Olivier Beaulieu
a5b4017d5e
Add is.enumCase and assert.enumCase (#150)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2022-01-17 12:55:40 +07:00
Sindre Sorhus
f5cc764e22 4.2.1 2022-01-07 21:35:19 +07:00
Stuart Dotson
ad661ebcee
Fix is.iterable and is.asyncIterable TypeScript types (#149) 2022-01-07 21:32:06 +07:00
Sindre Sorhus
a82aeeaa5e Add FAQ about instanceof 2021-10-31 12:34:45 +07:00
Sindre Sorhus
13b2343dfc 4.2.0 2021-09-13 21:27:03 +07:00
Kayson Wu
a8de3d6f34
Add is.formData and is.urlSearchParams (#139) 2021-09-13 21:25:44 +07:00
Sindre Sorhus
b007935b4b 4.1.0 2021-09-10 15:30:39 +07:00
PopGoesTheWza
d2f98e472d
Add is.propertyKey (#138)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Giora Guttsait <giora111@gmail.com>
2021-09-10 15:26:13 +07:00
Sindre Sorhus
6f2b24d822 Minor tweaks 2021-09-07 11:45:58 +07:00
Sindre Sorhus
238e8c80c7 4.0.1 2021-04-22 16:01:32 +07:00
Dave Cohen
b748ab72b6
Fix assertion message for .all and .any (#132) 2021-04-22 16:00:08 +07:00
Sindre Sorhus
5ed7e9bb40 Meta tweaks 2021-03-31 01:04:39 +07:00
Sindre Sorhus
4f8b01f2dc Rename master branch to main 2021-01-24 14:20:06 +07:00
Richie Bendall
da6bb531af
Move to GitHub Actions (#129) 2021-01-02 11:25:04 +07:00
Sindre Sorhus
d528545e02 4.0.0 2020-10-13 00:08:06 +02:00
Rocktim Saikia
94749dbb2e
Improve is.plainObject TypeScript type (#126) 2020-10-13 00:00:52 +02:00
Sindre Sorhus
bf6bba7af8 3.1.2 2020-08-22 00:19:30 +02:00
Arnovsky
d8ced89efe
Fix using is.array in is.all (#125) 2020-08-22 00:18:34 +02:00
Sindre Sorhus
5feadcb0b8 3.1.1 2020-08-16 12:30:54 +02:00
iyegoroff
4c29fb35cb
Improve import for VS Code (#122) 2020-08-16 12:29:46 +02:00
Sindre Sorhus
09d31733d3 3.1.0 2020-07-25 09:14:15 +02:00
Arnovsky
3f93bf200d
Add is.array overload that supports asserting array items (#119)
Co-authored-by: Pedro Augusto de Paula Barbosa <papb1996@gmail.com>
Co-authored-by: Giora Guttsait <giora111@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2020-07-25 09:11:59 +02:00
Richie Bendall
e31db97eab
Extract necessary functions from type-fest (#120) 2020-07-20 07:48:08 +08:00
Sindre Sorhus
4b35ad5bec 3.0.0 2020-06-28 04:22:15 +08:00
Bjorn Stromberg
47fa419e4f
Update devDependency @types/node from v13.7.4 to v14.0.13 (#116) 2020-06-28 04:20:49 +08:00
Bjorn Stromberg
71ca1e5573
Make the is() function type-safe (#117) 2020-06-28 04:20:36 +08:00
Bjorn Stromberg
a96abee1a3
Use shields.io for number of downloads per week (#118) 2020-06-27 19:13:23 +08:00
Bjorn Stromberg
1ffe2fb6a7
Use string literals instead of enums (#113) 2020-06-20 15:28:47 +08:00
Bjorn Stromberg
9d404cad2e
Test on Node.js 14 (#115) 2020-06-15 15:43:26 +08:00
Sindre Sorhus
fae0096eba 2.1.1 2020-04-19 18:18:00 +08:00
Arfat Salman
402fbb5a7e
Fix #109: is.numericString behaves correctly on whitespaces (#110) 2020-04-17 17:55:02 -04:00
Sindre Sorhus
05cdaccf92 Update TypeScript 2020-02-22 02:17:02 +07:00
Sindre Sorhus
1ff389cabb 2.1.0 2020-02-17 14:18:18 +07:00
Dave Cohen
d1929ad47c
Add support for multiple predicates to is.any (#104) 2020-02-16 20:06:19 -05:00
Sindre Sorhus
f97029fd73 Minor readme tweaks 2020-01-30 00:51:52 +07:00
Sindre Sorhus
863e26ad6a 2.0.0 2020-01-30 00:47:01 +07:00
Sindre Sorhus
5d0ccec21c Meta tweaks 2020-01-30 00:45:06 +07:00
Forresst
446a7a081e
Add .asyncGenerator and .asyncGeneratorFunction detection (#100) 2020-01-30 00:35:58 +07:00
Joel Purra
d28c86ee27
Propagate generic types where possible (#103) 2020-01-29 23:22:35 +07:00
Sindre Sorhus
11003b925e Meta tweaks 2020-01-22 19:17:43 +07:00
Joel Purra
0c3f110386 Add assertion type guards (#97) 2020-01-22 18:08:35 +07:00
Joel Purra
c842cc260f Upgrade dependencies (#101) 2020-01-21 23:56:44 +07:00
Sindre Sorhus
aeb3f74d65 Make the NodeStream type more accurate 2019-11-13 16:06:18 +07:00
Sindre Sorhus
c25b606c3b Improve the type assertion for is.asyncFunction 2019-11-07 16:37:36 +07:00
Sindre Sorhus
af6b03d67f Require Node.js 10 2019-11-07 15:58:29 +07:00
Blaine Bublitz
0cc82c583e Fix a readme link (#96) 2019-10-31 11:20:49 +07:00
Sindre Sorhus
8ff75abfff Tidelift tasks 2019-10-30 20:01:23 +07:00
Sindre Sorhus
e7277de849 1.2.0 2019-10-04 11:39:58 +07:00
Sindre Sorhus
3f2caa4835 Revert "Bundle the required DOM types (#93)"
This reverts commit 7c16f20d16.
2019-10-04 11:38:10 +07:00
Sindre Sorhus
4a63743feb 1.1.0 2019-10-03 15:00:03 +07:00
Sindre Sorhus
7c16f20d16
Bundle the required DOM types (#93)
Closes #92
2019-10-02 23:06:53 +07:00
Sindre Sorhus
0f9b8479e9 Tidelift tasks 2019-09-10 12:46:18 +07:00
Sindre Sorhus
0cbd9df6ce Minor refactoring 2019-07-01 23:19:25 +07:00
Sindre Sorhus
e358e44dd5 1.0.0 2019-06-30 15:19:21 +07:00
Sindre Sorhus
4f4820ef2f Meta tweaks 2019-06-30 15:18:24 +07:00
Kai Niedziela
f04dffa575 Make is.number(NaN) return false (#90)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2019-06-30 15:09:07 +07:00
Sindre Sorhus
ffc6ce4586 Fix linting 2019-06-15 02:12:31 +07:00
Sindre Sorhus
7bf407fbf1
Create funding.yml 2019-05-28 12:56:17 +07:00
Sindre Sorhus
878d111ae7 0.17.1 2019-05-21 16:48:34 +07:00
Sindre Sorhus
6106086a35 Revert "Drop duplicate export (#84)"
This reverts commit 28913cae88.

Closes #89
Fixes #88
2019-05-21 16:45:07 +07:00
Sindre Sorhus
b064473589 0.17.0 2019-05-13 11:07:28 +07:00
Sindre Sorhus
04cd282265 Fix the capitalization of is.bigInt64Array and is.bigUint64Array 2019-05-13 11:04:48 +07:00
Sindre Sorhus
9bc8307770 0.16.0 2019-05-04 16:13:44 +07:00
Sindre Sorhus
2dac8e96f4 Meta tweaks 2019-05-04 16:11:43 +07:00
Vlad Frangu
dd2a91dce5 Add support for BigInt (#87) 2019-05-04 16:05:23 +07:00
Adam Babcock
373605e40d Test coverage for is(value) (#86) 2019-04-28 15:15:11 +07:00
Sindre Sorhus
120f74ab63 Require Node.js 8 2019-04-01 04:02:25 +07:00
Sindre Sorhus
ea4204f0b4 Switch to XO for linting 2019-03-31 21:34:47 +07:00
Federico Brigante
28913cae88 Drop duplicate export (#84) 2019-03-14 16:32:19 +07:00
Sindre Sorhus
79144f9542 Readme tweaks 2019-02-12 14:40:44 +07:00
Sindre Sorhus
c66885b781 Add sideEffects key to package.json 2019-02-04 12:56:31 +07:00
Sindre Sorhus
0fff8265e6 Fix tests 2019-02-04 03:00:25 +07:00
Sindre Sorhus
3ec41686f7 0.15.0 2019-02-04 02:55:36 +07:00
Sindre Sorhus
2f5e03bed2 Minor tweaks 2019-02-04 02:54:30 +07:00
Sindre Sorhus
9683cd7fd9 Run TS as a require hook for tests instead of precompile 2019-02-04 02:38:38 +07:00
Sindre Sorhus
3c847be5a0 Improve the TypeScript types (#80) 2019-02-04 02:38:38 +07:00
Scottie Enriquez
2502442404 Rename .odd() to .oddInteger() and .even() to .evenInteger() for clarity (#77) 2019-02-04 02:38:38 +07:00
Sindre Sorhus
641d856b36
Stop using TypeScript namespace (#78) 2019-02-02 01:14:08 +07:00
Sindre Sorhus
ab586df0f9 Fix lint issue 2019-01-12 12:14:45 +07:00
Sindre Sorhus
0e1cce5d45
Fix readme typo 2019-01-11 16:34:29 +07:00
Itai Steinherz
4d0120adb7 Fix is.urlString documentation (#76) 2018-12-13 22:38:35 +01:00
Sindre Sorhus
6cb1d1e910 0.14.0 2018-12-13 16:58:24 +01:00
Sindre Sorhus
42fd8d3574 Use the URL global when available 2018-12-13 16:57:06 +01:00
Sindre Sorhus
844b43c9df
Improve the is.observable check (#74)
Fixes #72
2018-12-13 16:52:55 +01:00
Itai Steinherz
566f363632 Add is.urlString (#73) 2018-12-13 16:52:21 +01:00
Sindre Sorhus
2ee148f5a1 Meta tweaks 2018-12-13 00:58:02 +01:00
Sindre Sorhus
9df6f4ebe9 Bump TypeScript version 2018-11-30 15:14:41 +07:00
jokebookservice1
b8a9fb457c Minor documentational correction (#69) 2018-11-02 23:04:44 +07:00
Sindre Sorhus
2232eeea79 0.13.0 2018-11-02 19:08:53 +07:00
Sindre Sorhus
69bbf2d4be Readme improvements 2018-11-02 19:07:38 +07:00
Lukas Tetzlaff
d4869045c2 Refactor any to unknown where possible (#68)
Resolves #62
2018-11-02 17:43:51 +07:00
Itai Steinherz
7317226c80 Add is.numericString() (#67) 2018-11-01 18:21:49 +07:00
Sindre Sorhus
9ac56f1be7 Minor code style tweaks in the tests 2018-10-30 23:19:19 +07:00
Sindre Sorhus
c983ffa4cd 0.12.0 2018-09-28 13:35:34 +07:00
Sindre Sorhus
45c976071a Don't import util
We don't really need its full power. Not worth the bloat.
2018-09-28 13:32:55 +07:00
Arfat Salman
6e07df5896 Add emptiness methods (#61)
Fix #53
2018-09-28 13:24:35 +07:00
Sindre Sorhus
65c94f1a02 Include TS type lib references directly in the file
Fixes #51
2018-09-28 13:08:17 +07:00
Sam Verschueren
442f7b709f Use is-buffer ponyfill for better browser support (#66) 2018-09-27 02:02:41 +07:00
Alex Russell
ad6f372c47 Fix parameter naming of isAbsoluteMod2 function. (#64) 2018-09-18 19:22:55 +03:00
Sindre Sorhus
36b46f1889 Update dev dependencies 2018-07-31 02:17:39 +07:00
Sindre Sorhus
b2bb3e7d37 0.11.0 2018-07-10 16:56:38 +07:00
Artur Androsovych
3bdaf21475 Add is.urlInstance (#60) 2018-07-10 16:04:20 +07:00
Artur Androsovych
c8736c2972 Add is.asyncIterable (#59) 2018-07-10 00:35:16 +07:00
Sindre Sorhus
c84c2cbeca Don't publish the compiled test directory 2018-07-05 23:37:24 +07:00
Sindre Sorhus
d11b7eaaa1 0.10.0 2018-07-05 23:33:34 +07:00
Sindre Sorhus
ff268de3d0
Add related module to the readme 2018-06-30 02:07:02 +07:00
Sindre Sorhus
fe754b5528 Update dev dependencies 2018-06-01 21:28:26 +07:00
Sindre Sorhus
0988832ef7 Meta tweaks 2018-05-25 10:40:55 +07:00
Sindre Sorhus
db25d554dc TS config tweaks 2018-05-19 15:42:12 +07:00
Sindre Sorhus
37f6cc3fe3 0.9.0 2018-05-04 12:30:58 +07:00
Lukas Tetzlaff
1df2ff09ce Improve TS code by adding generics and removing any where applicable (#49) 2018-05-04 12:29:21 +07:00
Sam Verschueren
55c00956f9 Add is.observable (#50) 2018-05-03 10:22:32 +07:00
Sam Verschueren
38df0cfb24 Remove moot tslint disable comment (#46) 2018-04-04 13:08:29 +07:00
Sindre Sorhus
7ae4b44ca2 0.8.0 2018-04-04 00:10:07 +07:00
Sam Verschueren
8894dbec17 Add type guards (#43) 2018-04-04 00:05:59 +07:00
Amit Merchant
5670ed7a97 Minor readme improvement (#44) 2018-03-30 10:55:09 +07:00
Sindre Sorhus
64ced4d33c Simplify isFunctionOfType
ef85a5173d (r28310156)
2018-03-29 11:56:13 +07:00
Sindre Sorhus
ef85a5173d Drop support for Node.js 4
Fixes #41
Fixes #40
2018-03-28 02:25:21 +07:00
Sindre Sorhus
fd32b11b6d Bump TypeScript 2018-02-01 08:41:27 +07:00
Sindre Sorhus
40fc2fd790
Remove publishConfig from package.json
Apparently, it's only needed for the initial publish.
2018-01-29 21:55:09 +07:00
Sindre Sorhus
828a5b3088 0.7.0 2017-12-11 21:40:15 +01:00
Sindre Sorhus
28702421bf Add missing dataView method
Fixes #37
2017-12-11 21:38:58 +01:00
Brandon Smith
70b08940be
Add is.directInstanceOf() (#38) 2017-12-09 11:55:08 -05:00
Sindre Sorhus
4ce2ee9d39 package.json indentation 2017-12-02 12:10:04 +01:00
Sindre Sorhus
50e3fe88c7 0.6.0 2017-11-20 03:18:11 +07:00
Brandon Smith
a04a04c131 Add is.nodeStream() (#34) 2017-11-20 03:16:06 +07:00
Mario Nebl
ae3adc9818 Enumerate type names (#32) 2017-11-20 03:07:24 +07:00
Darren Scerri
319982a09c Add is.boundFunction() (#31) 2017-11-10 13:11:35 -05:00
Sindre Sorhus
89fc424975 Add has-emoji to the Related section in the readme
Closes #24
2017-11-08 17:22:23 +07:00
Sindre Sorhus
e8ac7dc4aa 0.5.0 2017-11-07 10:23:46 +07:00
Sindre Sorhus
89867fbc16 Various tweaks 2017-11-07 10:23:00 +07:00
Sindre Sorhus
59a638b216
Restore ability to use default export in CommonJS (#29)
So you can use `require('is')` instead of `require('is').default`.
2017-11-07 09:58:49 +07:00
Sindre Sorhus
d075b547fc Update tslint-xo 2017-11-06 23:00:28 +07:00
Sindre Sorhus
9770f66899 Cleanup 2017-11-06 22:36:51 +07:00
Lukas Tetzlaff
8d8fd2b7e0 Refactor module in TypeScript (#28) 2017-11-06 22:26:59 +07:00
Brandon Smith
83adc096ef Add is.arrayLike() (#26) 2017-10-26 09:30:17 -04:00
Sindre Sorhus
0bafa04e77 Welcome @brandon93s to the project 🎉🌟 2017-10-23 19:04:11 +07:00
Sindre Sorhus
bd428997a2 Remove trailing whitespace 2017-10-23 19:03:35 +07:00
Sindre Sorhus
a4eebe4b4a 0.4.0 2017-10-22 02:28:27 +07:00
Brandon Smith
dfcdfc3a83 Add is.truthy() and is.falsy() (#25) 2017-10-20 17:49:52 +03:00
Brandon Smith
cdd4829edf Add is.emptyOrWhitespace() (#21) 2017-10-17 23:46:58 +03:00
Brandon Smith
615932d6c2 Add is.even() and is.odd() (#23) 2017-10-17 22:36:10 +07:00
Brandon Smith
00974a2fe9 Add is.safeInteger() (#22) 2017-10-17 18:19:17 +03:00
Brandon Smith
dc3b6ff86b Add is.asyncFunction (#20) 2017-10-16 10:29:10 +07:00
Sindre Sorhus
04cb80dfb1 0.3.0 2017-10-11 16:51:12 +07:00
Kodie Grantham
651f434eab Add is.any() and is.all() methods (#19) 2017-10-11 16:26:45 +07:00
Melvin
75ac3cd574 Add is.domElement() (#11) 2017-10-07 23:19:11 +07:00
Melvin
6268253ec6 Add link to is-blob (#17) 2017-10-06 14:48:04 +07:00
Kodie Grantham
46e886d10b Add is.empty() (#16) 2017-10-06 14:39:36 +07:00
Khaled Al-Ansari
ee8f5d16f8 Update is.boolean() method (#15) 2017-10-05 20:56:23 +07:00
Melvin Philips
24c964a7c7 Add is.infinite() 2017-10-05 18:52:27 +07:00
Sindre Sorhus
11b98171c8 0.2.1 2017-10-05 11:21:46 +07:00
Sindre Sorhus
47982af117 Fix silly null check mistake
Fixes #13
2017-10-05 11:20:39 +07:00
19 changed files with 6359 additions and 597 deletions

3
.gitattributes vendored
View file

@ -1,2 +1 @@
* text=auto
*.js text eol=lf
* text=auto eol=lf

3
.github/security.md vendored Normal file
View file

@ -0,0 +1,3 @@
# Security Policy
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.

21
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: CI
on:
- push
- pull_request
jobs:
test:
name: Node.js ${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version:
- 24
- 22
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
node_modules
yarn.lock
/distribution
.tsimp

View file

@ -1,5 +0,0 @@
language: node_js
node_js:
- '8'
- '6'
- '4'

9
AGENTS.md Normal file
View file

@ -0,0 +1,9 @@
# Notes
## Branded types for type guards
TypeScript type guards narrow in both branches. If `is.integer(n)` returns `value is number` and the input is `number`, the false branch computes `Exclude<number, number>` = `never`. This makes common patterns like `if (!is.integer(n)) throw; use(n)` fail because `n` becomes `never` after the guard.
To avoid this, type guard predicates use branded types (e.g., `number & {readonly __brand: 'Integer'}`, `string & {readonly __brand: 'UrlString'}`). A branded subtype ensures the false branch stays the original type (e.g., `Exclude<number, Integer>` = `number`).
Assert functions (`asserts value is T`) don't need branded types since they throw on failure and have no false branch. They use plain types like `asserts value is number`.

1
CLAUDE.md Symbolic link
View file

@ -0,0 +1 @@
AGENTS.md

164
index.js
View file

@ -1,164 +0,0 @@
'use strict';
const util = require('util');
const toString = Object.prototype.toString;
const getObjectType = x => toString.call(x).slice(8, -1);
const isOfType = type => x => typeof x === type; // eslint-disable-line valid-typeof
const isObjectOfType = type => x => getObjectType(x) === type;
const is = value => {
if (value == null) { // eslint-disable-line no-eq-null, eqeqeq
return 'null';
}
if (value === true || value === false) {
return 'boolean';
}
const type = typeof value;
if (type === 'undefined') {
return 'undefined';
}
if (type === 'string') {
return 'string';
}
if (type === 'number') {
return 'number';
}
if (type === 'symbol') {
return 'symbol';
}
if (is.function(value)) {
return 'Function';
}
if (Array.isArray(value)) {
return 'Array';
}
if (Buffer.isBuffer(value)) {
return 'Buffer';
}
const tagType = getObjectType(value);
if (tagType) {
return tagType;
}
if (value instanceof String || value instanceof Boolean || value instanceof Number) {
throw new TypeError('Please don\'t use object wrappers for primitive types');
}
return 'Object';
};
is.undefined = isOfType('undefined');
is.null = x => x === null;
is.string = isOfType('string');
is.number = isOfType('number');
is.boolean = isOfType('boolean');
is.symbol = isOfType('symbol');
is.array = Array.isArray;
is.function = isOfType('function');
is.buffer = Buffer.isBuffer;
const isObject = x => typeof x === 'object';
is.object = x => !is.nullOrUndefined(x) && (is.function(x) || isObject(x));
is.nativePromise = isObjectOfType('Promise');
const hasPromiseAPI = x =>
!is.null(x) &&
isObject(x) &&
is.function(x.then) &&
is.function(x.catch);
is.promise = x => is.nativePromise(x) || hasPromiseAPI(x);
is.generator = x => is.iterable(x) && is.function(x.next) && is.function(x.throw);
// TODO: Change to use `isObjectOfType` once Node.js 6 or higher is targeted
is.generatorFunction = x => is.function(x) && is.function(x.constructor) && x.constructor.name === 'GeneratorFunction';
is.regExp = isObjectOfType('RegExp');
is.date = isObjectOfType('Date');
is.error = isObjectOfType('Error');
is.map = isObjectOfType('Map');
is.set = isObjectOfType('Set');
is.weakMap = isObjectOfType('WeakMap');
is.weakSet = isObjectOfType('WeakSet');
is.int8Array = isObjectOfType('Int8Array');
is.uint8Array = isObjectOfType('Uint8Array');
is.uint8ClampedArray = isObjectOfType('Uint8ClampedArray');
is.int16Array = isObjectOfType('Int16Array');
is.uint16Array = isObjectOfType('Uint16Array');
is.int32Array = isObjectOfType('Int32Array');
is.uint32Array = isObjectOfType('Uint32Array');
is.float32Array = isObjectOfType('Float32Array');
is.float64Array = isObjectOfType('Float64Array');
is.arrayBuffer = isObjectOfType('ArrayBuffer');
is.sharedArrayBuffer = isObjectOfType('SharedArrayBuffer');
is.nan = Number.isNaN;
is.nullOrUndefined = x => is.null(x) || is.undefined(x);
const primitiveTypes = new Set([
'undefined',
'string',
'number',
'boolean',
'symbol'
]);
is.primitive = x => is.null(x) || primitiveTypes.has(typeof x);
is.integer = Number.isInteger;
is.plainObject = x => {
// From: https://github.com/sindresorhus/is-plain-obj/blob/master/index.js
let prototype;
// eslint-disable-next-line no-return-assign
return getObjectType(x) === 'Object' &&
(prototype = Object.getPrototypeOf(x), prototype === null ||
prototype === Object.getPrototypeOf({}));
};
is.iterable = x => !is.nullOrUndefined(x) && is.function(x[Symbol.iterator]);
is.class = x => is.function(x) && x.toString().startsWith('class ');
const typedArrayTypes = new Set([
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array'
]);
is.typedArray = x => typedArrayTypes.has(getObjectType(x));
is.inRange = (x, range) => {
if (is.number(range)) {
return x >= Math.min(0, range) && x <= Math.max(range, 0);
}
if (is.array(range) && range.length === 2) {
// TODO: Use spread operator here when targeting Node.js 6 or higher
return x >= Math.min.apply(null, range) && x <= Math.max.apply(null, range);
}
throw new TypeError(`Invalid range: ${util.inspect(range)}`);
};
module.exports = is;

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
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:

View file

@ -1,49 +1,76 @@
{
"name": "@sindresorhus/is",
"version": "0.2.0",
"description": "Type check values: `is.string('🦄') //=> true`",
"license": "MIT",
"repository": "sindresorhus/is",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=4"
},
"scripts": {
"test": "xo && ava"
},
"files": [
"index.js"
],
"keywords": [
"type",
"types",
"is",
"check",
"checking",
"validate",
"validation",
"utility",
"util",
"typeof",
"instanceof",
"object",
"assert",
"assertion",
"test",
"kind",
"primitive",
"verify",
"compare"
],
"devDependencies": {
"ava": "*",
"xo": "*"
}
"name": "@sindresorhus/is",
"version": "8.1.0",
"description": "Type check values",
"license": "MIT",
"repository": "sindresorhus/is",
"funding": "https://github.com/sindresorhus/is?sponsor=1",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": {
"types": "./distribution/index.d.ts",
"default": "./distribution/index.js"
},
"sideEffects": false,
"engines": {
"node": ">=22"
},
"scripts": {
"build": "del distribution && tsc",
"test": "tsc --noEmit && tsc --project test/tsconfig.json --noEmit && xo && node --experimental-transform-types --test test/test.ts",
"prepare": "npm run build"
},
"files": [
"distribution"
],
"keywords": [
"type",
"types",
"is",
"check",
"checking",
"validate",
"validation",
"utility",
"util",
"typeof",
"instanceof",
"object",
"assert",
"assertion",
"test",
"kind",
"primitive",
"verify",
"compare",
"typescript",
"typeguards",
"types"
],
"xo": {
"rules": {
"@typescript-eslint/no-unsafe-enum-comparison": "off",
"@typescript-eslint/no-confusing-void-expression": "off",
"@typescript-eslint/no-unsafe-type-assertion": "off",
"@stylistic/operator-linebreak": "off"
}
},
"devDependencies": {
"@sindresorhus/tsconfig": "^8.1.0",
"@types/jsdom": "^28.0.1",
"@types/node": "^25.5.2",
"@types/zen-observable": "^0.8.7",
"del-cli": "^7.0.0",
"expect-type": "^1.3.0",
"jsdom": "^29.0.2",
"rxjs": "^7.8.2",
"tempy": "^3.2.0",
"typescript": "6.0.2",
"xo": "^2.0.2",
"zen-observable": "^0.10.0"
}
}

774
readme.md
View file

@ -1,21 +1,30 @@
# is [![Build Status](https://travis-ci.org/sindresorhus/is.svg?branch=master)](https://travis-ci.org/sindresorhus/is)
# is
> Type check values: `is.string('🦄') //=> true`
> Type check values
For example, `is.string('🦄') //=> true`
<img src="header.gif" width="182" align="right">
## Highlights
- Written in TypeScript
- [Extensive use of type guards](#type-guards)
- [Supports type assertions](#type-assertions)
- [Aware of generic type parameters](#generic-type-parameters) (use with caution)
- Actively maintained
- ![Millions of downloads per week](https://img.shields.io/npm/dw/@sindresorhus/is)
## Install
```sh
npm install @sindresorhus/is
```
$ npm install @sindresorhus/is
```
## Usage
```js
const is = require('@sindresorhus/is');
import is from '@sindresorhus/is';
is('🦄');
//=> 'string'
@ -27,6 +36,44 @@ is.number(6);
//=> true
```
[Assertions](#type-assertions) perform the same type checks, but throw an error if the type does not match.
```js
import {assert} from '@sindresorhus/is';
assert.string(2);
//=> Error: Expected value which is `string`, received value of type `number`.
```
Assertions (except `assertAll` and `assertAny`) also support an optional custom error message.
```js
import {assert} from '@sindresorhus/is';
assert.nonEmptyString(process.env.API_URL, 'The API_URL environment variable is required.');
//=> Error: The API_URL environment variable is required.
```
And with TypeScript:
```ts
import {assert} from '@sindresorhus/is';
assert.string(foo);
// `foo` is now typed as a `string`.
```
### Named exports
Named exports allow tooling to perform tree-shaking, potentially reducing bundle size by including only code from the methods that are used.
Every method listed below is available as a named export. Each method is prefixed by either `is` or `assert` depending on usage.
For example:
```js
import {assertNull, isUndefined} from '@sindresorhus/is';
```
## API
@ -46,30 +93,72 @@ Example:
- `'Function'`
- `'Object'`
Note: It will throw if you try to feed it object-wrapped primitives, as that's a bad practice. For example `new String('foo')`.
This method is also exported as `detect`. You can import it like this:
```js
import {detect} from '@sindresorhus/is';
```
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')`.
### is.{method}
All the below methods accept a value and returns a boolean for whether the value is of the desired type.
All the below methods accept a value and return a boolean for whether the value is of the desired type.
#### Primitives
##### .undefined(value)
##### .null(value)
##### .string(value)
##### .number(value)
Note: `is.number(NaN)` returns `false`. This intentionally deviates from `typeof` behavior to increase user-friendliness of `is` type checks.
##### .boolean(value)
##### .symbol(value)
##### .bigint(value)
#### Built-in types
##### .array(value)
##### .array(value, assertion?)
Returns true if `value` is an array and all of its items match the assertion (if provided).
```js
is.array(value); // Validate `value` is an array.
is.array(value, is.number); // Validate `value` is an array and all of its items are numbers.
```
##### .arrayOf(predicate)
Returns a type guard that checks if `value` is an array where every item matches the predicate. Useful for composing with other methods.
```js
const isStringArray = is.arrayOf(is.string);
isStringArray(['a', 'b']); //=> true
isStringArray(['a', 1]); //=> false
```
##### .function(value)
##### .buffer(value)
> [!NOTE]
> [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer)
##### .blob(value)
##### .object(value)
Keep in mind that [functions are objects too](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions).
##### .numericString(value)
Returns `true` for a string that represents a number satisfying `is.number`, for example, `'42'` and `'-8.3'`.
Note: `'NaN'` returns `false`, but `'Infinity'` and `'-Infinity'` return `true`.
##### .regExp(value)
##### .date(value)
##### .error(value)
@ -84,10 +173,70 @@ Returns `true` for any object that implements its own `.next()` and `.throw()` m
##### .generatorFunction(value)
##### .asyncFunction(value)
Returns `true` for any `async` function that can be called with the `await` operator.
```js
is.asyncFunction(async () => {});
//=> true
is.asyncFunction(() => {});
//=> false
```
##### .asyncGenerator(value)
```js
is.asyncGenerator(
(async function * () {
yield 4;
})()
);
//=> true
is.asyncGenerator(
(function * () {
yield 4;
})()
);
//=> false
```
##### .asyncGeneratorFunction(value)
```js
is.asyncGeneratorFunction(async function * () {
yield 4;
});
//=> true
is.asyncGeneratorFunction(function * () {
yield 4;
});
//=> false
```
##### .boundFunction(value)
Returns `true` for any `bound` function.
```js
is.boundFunction(() => {});
//=> true
is.boundFunction(function () {}.bind(null));
//=> true
is.boundFunction(function () {});
//=> false
```
##### .map(value)
##### .set(value)
##### .weakMap(value)
##### .weakSet(value)
##### .weakRef(value)
#### Typed arrays
@ -100,6 +249,8 @@ Returns `true` for any object that implements its own `.next()` and `.throw()` m
##### .uint32Array(value)
##### .float32Array(value)
##### .float64Array(value)
##### .bigInt64Array(value)
##### .bigUint64Array(value)
#### Structured data
@ -107,26 +258,250 @@ Returns `true` for any object that implements its own `.next()` and `.throw()` m
##### .sharedArrayBuffer(value)
##### .dataView(value)
##### .enumCase(value, enum)
TypeScript-only. Returns `true` if `value` is a member of `enum`.
```ts
enum Direction {
Ascending = 'ascending',
Descending = 'descending'
}
is.enumCase('ascending', Direction);
//=> true
is.enumCase('other', Direction);
//=> false
```
#### Emptiness
##### .emptyString(value)
Returns `true` if the value is a `string` and the `.length` is 0.
##### .emptyStringOrWhitespace(value)
Returns `true` if `is.emptyString(value)` or if it's a `string` that is all whitespace.
##### .nonEmptyString(value)
Returns `true` if the value is a `string` and the `.length` is more than 0.
##### .nonEmptyStringAndNotWhitespace(value)
Returns `true` if the value is a `string` that is not empty and not whitespace.
```js
const values = ['property1', '', null, 'property2', ' ', undefined];
values.filter(is.nonEmptyStringAndNotWhitespace);
//=> ['property1', 'property2']
```
##### .emptyArray(value)
Returns `true` if the value is an `Array` and the `.length` is 0.
##### .nonEmptyArray(value)
Returns `true` if the value is an `Array` and the `.length` is more than 0.
##### .emptyObject(value)
Returns `true` if the value is an `Object` and `Object.keys(value).length` is 0.
Please note that `Object.keys` returns only own enumerable properties. Hence something like this can happen:
```js
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: true,
enumerable: false,
configurable: true
});
is.emptyObject(object1);
//=> true
```
##### .nonEmptyObject(value)
Returns `true` if the value is an `Object` and `Object.keys(value).length` is more than 0.
##### .emptySet(value)
Returns `true` if the value is a `Set` and the `.size` is 0.
##### .nonEmptySet(Value)
Returns `true` if the value is a `Set` and the `.size` is more than 0.
##### .emptyMap(value)
Returns `true` if the value is a `Map` and the `.size` is 0.
##### .nonEmptyMap(value)
Returns `true` if the value is a `Map` and the `.size` is more than 0.
#### Miscellaneous
##### .directInstanceOf(value, class)
Returns `true` if `value` is a direct instance of `class`.
```js
is.directInstanceOf(new Error(), Error);
//=> true
class UnicornError extends Error {}
is.directInstanceOf(new UnicornError(), Error);
//=> false
```
##### .urlInstance(value)
Returns `true` if `value` is an instance of the [`URL` class](https://developer.mozilla.org/en-US/docs/Web/API/URL).
```js
const url = new URL('https://example.com');
is.urlInstance(url);
//=> true
```
##### .urlString(value)
Returns `true` if `value` is a URL string.
Note: this only does basic checking using the [`URL` class](https://developer.mozilla.org/en-US/docs/Web/API/URL) constructor.
```js
const url = 'https://example.com';
is.urlString(url);
//=> true
is.urlString(new URL(url));
//=> false
```
##### .truthy(value)
Returns `true` for all values that evaluate to true in a boolean context:
```js
is.truthy('🦄');
//=> true
is.truthy(undefined);
//=> false
```
##### .falsy(value)
Returns `true` if `value` is one of: `false`, `0`, `''`, `null`, `undefined`, `NaN`.
##### .nan(value)
##### .nullOrUndefined(value)
##### .primitive(value)
JavaScript primitives are as follows: `null`, `undefined`, `string`, `number`, `boolean`, `symbol`.
JavaScript primitives are as follows:
- `null`
- `undefined`
- `string`
- `number`
- `boolean`
- `symbol`
- `bigint`
##### .integer(value)
##### .safeInteger(value)
Returns `true` if `value` is a [safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger).
##### .plainObject(value)
An object is plain if it's created by either `{}`, `new Object()`, or `Object.create(null)`.
##### .iterable(value)
##### .asyncIterable(value)
##### .class(value)
Returns `true` for instances created by a ES2015 class.
Returns `true` if the value is a class constructor.
##### .typedArray(value)
##### .arrayLike(value)
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.
```js
is.arrayLike(document.forms);
//=> true
function foo() {
is.arrayLike(arguments);
//=> true
}
foo();
```
##### .tupleLike(value, guards)
A `value` is tuple-like if it matches the provided `guards` array both in `.length` and in types.
```js
is.tupleLike([1], [is.number]);
//=> true
```
```js
function foo() {
const tuple = [1, '2', true];
if (is.tupleLike(tuple, [is.number, is.string, is.boolean])) {
tuple // [number, string, boolean]
}
}
foo();
```
##### .finiteNumber(value)
Check if `value` is a number and is finite. Excludes `Infinity` and `-Infinity`.
##### .positiveNumber(value)
Check if `value` is a number and is more than 0.
##### .negativeNumber(value)
Check if `value` is a number and is less than 0.
##### .nonNegativeNumber(value)
Check if `value` is a number and is 0 or more.
##### .positiveInteger(value)
Check if `value` is an integer and is more than 0.
##### .negativeInteger(value)
Check if `value` is an integer and is less than 0.
##### .nonNegativeInteger(value)
Check if `value` is an integer and is 0 or more.
##### .inRange(value, range)
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.
@ -145,6 +520,368 @@ Check if `value` (number) is in the range of `0` to `upperBound`.
is.inRange(3, 10);
```
##### .htmlElement(value)
Returns `true` if `value` is an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement).
##### .nodeStream(value)
Returns `true` if `value` is a Node.js [stream](https://nodejs.org/api/stream.html).
```js
import fs from 'node:fs';
is.nodeStream(fs.createReadStream('unicorn.png'));
//=> true
```
##### .observable(value)
Returns `true` if `value` is an `Observable`.
```js
import {Observable} from 'rxjs';
is.observable(new Observable());
//=> true
```
##### .infinite(value)
Check if `value` is `Infinity` or `-Infinity`.
##### .evenInteger(value)
Returns `true` if `value` is an even integer.
##### .oddInteger(value)
Returns `true` if `value` is an odd integer.
##### .propertyKey(value)
Returns `true` if `value` can be used as an object property key (either `string`, `number`, or `symbol`).
##### .formData(value)
Returns `true` if `value` is an instance of the [`FormData` class](https://developer.mozilla.org/en-US/docs/Web/API/FormData).
```js
const data = new FormData();
is.formData(data);
//=> true
```
##### .urlSearchParams(value)
Returns `true` if `value` is an instance of the [`URLSearchParams` class](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams).
```js
const searchParams = new URLSearchParams();
is.urlSearchParams(searchParams);
//=> true
```
##### .any(predicate | predicate[], ...values)
Using a single `predicate` argument, returns `true` if **any** of the input `values` returns true in the `predicate`:
```js
is.any(is.string, {}, true, '🦄');
//=> true
is.any(is.boolean, 'unicorns', [], new Map());
//=> false
```
Using an array of `predicate[]`, returns `true` if **any** of the input `values` returns true for **any** of the `predicates` provided in an array:
```js
is.any([is.string, is.number], {}, true, '🦄');
//=> true
is.any([is.boolean, is.number], 'unicorns', [], new Map());
//=> false
```
##### .any(predicate[])
Using an array of `predicate[]` without values, returns a combined type guard that checks if a value matches **any** of the predicates:
```js
const isStringOrNumber = is.any([is.string, is.number]);
isStringOrNumber('hello');
//=> true
isStringOrNumber(123);
//=> true
isStringOrNumber(true);
//=> false
```
This is useful for composing with other methods like `is.optional`:
```js
is.optional(value, is.any([is.string, is.number]));
```
An empty predicate array currently returns a predicate that always returns `false`. This will throw in the next major release.
##### .all(predicate, ...values)
Returns `true` if **all** of the input `values` returns true in the `predicate`:
```js
is.all(is.object, {}, new Map(), new Set());
//=> true
is.all(is.string, '🦄', [], 'unicorns');
//=> false
```
##### .all(predicate[])
Using an array of `predicate[]` without values, returns a combined type guard that checks if a value matches **all** of the predicates:
```js
const isArrayAndNonEmpty = is.all([is.array, is.nonEmptyArray]);
isArrayAndNonEmpty(['hello']);
//=> true
isArrayAndNonEmpty([]);
//=> false
```
This is useful for composing with other methods like `is.optional`:
```js
is.optional(value, is.all([is.object, is.plainObject]));
```
An empty predicate array currently returns a predicate that always returns `true`. This will throw in the next major release.
##### .optional(value, predicate)
Returns `true` if `value` is `undefined` or satisfies the given `predicate`.
```js
is.optional(undefined, is.string);
//=> true
is.optional('🦄', is.string);
//=> true
is.optional(123, is.string);
//=> false
```
##### .oneOf(values)
Returns a type guard that checks if `value` is one of the given `values`. Best used with `as const` for precise type narrowing.
```ts
const isDirection = is.oneOf(['north', 'south', 'east', 'west'] as const);
isDirection('north'); //=> true
isDirection('up'); //=> false
```
##### .validDate(value)
Returns `true` if the value is a valid date.
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.
```js
const valid = new Date('2000-01-01');
is.date(valid);
//=> true
valid.getTime();
//=> 946684800000
valid.toUTCString();
//=> 'Sat, 01 Jan 2000 00:00:00 GMT'
is.validDate(valid);
//=> true
const invalid = new Date('Not a parsable date string');
is.date(invalid);
//=> true
invalid.getTime();
//=> NaN
invalid.toUTCString();
//=> 'Invalid Date'
is.validDate(invalid);
//=> false
```
##### .validLength(value)
Returns `true` if the value is a safe integer that is greater than or equal to zero.
This can be useful to confirm that a value is a valid count of something, ie. 0 or more.
##### .whitespaceString(value)
Returns `true` if the value is a string with only whitespace characters.
## Type guards
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.
```ts
import is from '@sindresorhus/is';
const padLeft = (value: string, padding: string | number) => {
if (is.number(padding)) {
// `padding` is typed as `number`
return Array(padding + 1).join(' ') + value;
}
if (is.string(padding)) {
// `padding` is typed as `string`
return padding + value;
}
throw new TypeError(`Expected 'padding' to be of type 'string' or 'number', got '${is(padding)}'.`);
}
padLeft('🦄', 3);
//=> ' 🦄'
padLeft('🦄', '🌈');
//=> '🌈🦄'
```
## Type assertions
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.
```ts
import {assert} from '@sindresorhus/is';
const handleMovieRatingApiResponse = (response: unknown) => {
assert.plainObject(response);
// `response` is now typed as a plain `object` with `unknown` properties.
assert.number(response.rating);
// `response.rating` is now typed as a `number`.
assert.string(response.title);
// `response.title` is now typed as a `string`.
return `${response.title} (${response.rating * 10})`;
};
handleMovieRatingApiResponse({rating: 0.87, title: 'The Matrix'});
//=> 'The Matrix (8.7)'
// This throws an error.
handleMovieRatingApiResponse({rating: '🦄'});
```
### Negative assertion
Asserts that `value` is not the specified type. Only exact, type-safe negative assertions are exposed.
Supported assertions:
- `assert.not.undefined(value)`
- `assert.not.null(value)`
- `assert.not.nullOrUndefined(value)`
- `assert.not.string(value)`
- `assert.not.boolean(value)`
- `assert.not.symbol(value)`
- `assert.not.bigint(value)`
- `assert.not.primitive(value)`
This intentionally excludes checks that cannot produce a safe TypeScript complement: `number` because `is.number` rejects `NaN`, refinements such as `integer` and `validDate`, and branded structural object checks such as `map` and `date`. Broad object checks such as `object` are also excluded to keep negative assertions limited to primitive and nullish types.
```ts
import {assert} from '@sindresorhus/is';
const value: string | undefined = getValue();
assert.not.undefined(value);
// Throws if `value` is `undefined`. Otherwise, `value` is now typed as `string`.
```
For `unknown` input, exact negative assertions narrow to the remaining representable type:
```ts
const value: unknown = getValue();
assert.not.nullOrUndefined(value);
// `value` is now typed as non-nullish.
assert.not.primitive(value);
// `value` is now typed as `object`.
```
### Optional assertion
Asserts that `value` is `undefined` or satisfies the provided `assertion`.
```ts
import {assert} from '@sindresorhus/is';
assert.optional(undefined, assert.string);
// Passes without throwing
assert.optional('🦄', assert.string);
// Passes without throwing
assert.optional(123, assert.string);
// Throws: Expected value which is `string`, received value of type `number`
```
## Generic type parameters
The type guards and type assertions are aware of [generic type parameters](https://www.typescriptlang.org/docs/handbook/generics.html), such as `Promise<T>` and `Map<Key, Value>`. 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.
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`.
```ts
import {assert} from '@sindresorhus/is';
async function badNumberAssumption(input: unknown) {
// Bad assumption about the generic type parameter fools the compile-time type system.
assert.promise<number>(input);
// `input` is a `Promise` but only assumed to be `Promise<number>`.
const resolved = await input;
// `resolved` is typed as `number` but was not actually checked at runtime.
// Multiplication will return NaN if the input promise did not actually contain a number.
return 2 * resolved;
}
async function goodNumberAssertion(input: unknown) {
assert.promise(input);
// `input` is typed as `Promise<unknown>`
const resolved = await input;
// `resolved` is typed as `unknown`
assert.number(resolved);
// `resolved` is typed as `number`
// Uses runtime checks so only numbers will reach the multiplication.
return 2 * resolved;
}
badNumberAssumption(Promise.resolve('An unexpected string'));
//=> NaN
// This correctly throws an error because of the unexpected string value.
goodNumberAssertion(Promise.resolve('An unexpected string'));
```
## FAQ
@ -163,9 +900,13 @@ For the ones I found, pick 3 of these.
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.
### Why not just use `instanceof` instead of this package?
`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.
## Related
- [environment](https://github.com/sindresorhus/environment) - Check which JavaScript environment your code is running in at runtime
- [is-stream](https://github.com/sindresorhus/is-stream) - Check if something is a Node.js stream
- [is-observable](https://github.com/sindresorhus/is-observable) - Check if a value is an Observable
- [file-type](https://github.com/sindresorhus/file-type) - Detect the file type of a Buffer/Uint8Array
@ -173,14 +914,11 @@ The most common mistakes I noticed in these modules was using `instanceof` for t
- [is-array-sorted](https://github.com/sindresorhus/is-array-sorted) - Check if an Array is sorted
- [is-error-constructor](https://github.com/sindresorhus/is-error-constructor) - Check if a value is an error constructor
- [is-empty-iterable](https://github.com/sindresorhus/is-empty-iterable) - Check if an Iterable is empty
- [is-blob](https://github.com/sindresorhus/is-blob) - Check if a value is a Blob - File-like object of immutable, raw data
- [has-emoji](https://github.com/sindresorhus/has-emoji) - Check whether a string has any emoji
## Created by
## Maintainers
- [Sindre Sorhus](https://github.com/sindresorhus)
- [Giora Guttsait](https://github.com/gioragutt)
## License
MIT
- [Brandon Smith](https://github.com/brandon93s)

2038
source/index.ts Normal file

File diff suppressed because it is too large Load diff

199
source/types.ts Normal file
View file

@ -0,0 +1,199 @@
// Extracted from https://github.com/sindresorhus/type-fest/blob/78019f42ea888b0cdceb41a4a78163868de57555/index.d.ts
/**
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
*/
export type Primitive =
// eslint-disable-next-line @typescript-eslint/no-restricted-types
| null
| undefined
| string
| number
| boolean
| symbol
| bigint;
/**
Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
*/
type Constructor<T, Arguments extends unknown[] = any[]> = new(...arguments_: Arguments) => T;
/**
Matches a [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
*/
export type Class<T, Arguments extends unknown[] = any[]> = Constructor<T, Arguments> & {prototype: T};
/**
Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`.
*/
export type TypedArray =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array;
declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- This must be an `interface` so it can be merged.
interface SymbolConstructor {
readonly observable: symbol;
}
}
/**
Matches a value that is like an [Observable](https://github.com/tc39/proposal-observable).
*/
export type ObservableLike = {
subscribe(observer: (value: unknown) => void): void;
[Symbol.observable](): ObservableLike;
};
// eslint-disable-next-line @typescript-eslint/no-restricted-types
export type Falsy = false | 0 | 0n | '' | null | undefined;
// eslint-disable-next-line @typescript-eslint/no-restricted-types
export type WeakRef<T extends object> = {
readonly [Symbol.toStringTag]: 'WeakRef';
deref(): T | undefined;
};
export type ArrayLike<T> = {
readonly [index: number]: T;
readonly length: number;
};
export type NodeStream = {
pipe<T extends NodeJS.WritableStream>(destination: T, options?: {end?: boolean}): T;
} & NodeJS.EventEmitter;
export type Predicate = (value: unknown) => boolean;
export type NonEmptyString = string & {0: string};
export type Whitespace = ' ';
type Brand<Key extends string> = Readonly<Record<Key, true>>;
/**
A string that represents a valid URL.
This is a branded type to prevent incorrect TypeScript type narrowing.
*/
export type UrlString = string & {readonly __brand: 'UrlString'};
// Keep numeric guards branded and simple. This intentionally favors correct false-branch narrowing for `number` inputs over perfect success-branch narrowing for numeric literal unions.
/**
The IEEE 754 "Not-a-Number" value, typed as a subtype of `number`.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type NaN = number & Brand<'__nanBrand'>;
/**
A finite number (excludes `NaN`, `Infinity`, and `-Infinity`).
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type FiniteNumber = number & Brand<'__finiteNumberBrand'>;
/**
A number greater than or equal to zero.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type NonNegativeNumber = number & Brand<'__nonNegativeNumberBrand'>;
/**
An integer value (no fractional part).
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type Integer = FiniteNumber & Brand<'__integerBrand'>;
/**
A number greater than zero.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type PositiveNumber = NonNegativeNumber & Brand<'__positiveNumberBrand'>;
/**
A number less than zero.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type NegativeNumber = number & Brand<'__negativeNumberBrand'>;
/**
An integer less than zero.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type NegativeInteger = Integer & NegativeNumber & Brand<'__negativeIntegerBrand'>;
/**
An integer greater than or equal to zero.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type NonNegativeInteger = Integer & NonNegativeNumber & Brand<'__nonNegativeIntegerBrand'>;
/**
An integer greater than zero.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type PositiveInteger = NonNegativeInteger & PositiveNumber & Brand<'__positiveIntegerBrand'>;
// Note: type-fest uses the `1e999` overflow trick to represent these types (since TypeScript has
// no built-in Infinity type), but we use branded types here for consistency and to avoid
// relying on numeric overflow behavior.
/**
A positive infinite number (`Infinity`).
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type PositiveInfinity = PositiveNumber & Brand<'__positiveInfinityBrand'>;
/**
A negative infinite number (`-Infinity`).
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type NegativeInfinity = NegativeNumber & Brand<'__negativeInfinityBrand'>;
/**
A safe integer (within the range of `Number.MIN_SAFE_INTEGER` to `Number.MAX_SAFE_INTEGER`).
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type SafeInteger = Integer & Brand<'__safeIntegerBrand'>;
/**
An even integer.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type EvenInteger = Integer & Brand<'__evenIntegerBrand'>;
/**
An odd integer.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type OddInteger = Integer & Brand<'__oddIntegerBrand'>;
/**
A non-negative safe integer, suitable as an array or string length.
Branded to prevent false-branch narrowing to `never` when the input is `number`.
*/
export type ValidLength = SafeInteger & NonNegativeInteger & Brand<'__validLengthBrand'>;

3
source/utilities.ts Normal file
View file

@ -0,0 +1,3 @@
export function keysOf<T extends Record<PropertyKey, unknown>>(value: T): Array<keyof T> {
return Object.keys(value) as Array<keyof T>; // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
}

360
test.js
View file

@ -1,360 +0,0 @@
import util from 'util';
import test from 'ava';
import m from '.';
const isNode8orHigher = Number(process.versions.node.split('.')[0]) >= 8;
const PromiseSubclassFixture = class extends Promise {};
const ErrorSubclassFixture = class extends Error {};
const types = new Map([
['undefined', undefined],
['null', null],
['string', [
'🦄',
'hello world',
''
]],
['number', [
6,
1.4,
0,
-0,
Infinity,
-Infinity
]],
['boolean', [
true,
false
]],
['symbol', Symbol('🦄')],
['array', [
[1, 2],
new Array(2)
]],
['function', [
function foo() {}, // eslint-disable-line func-names
function () {},
() => {},
async function () {},
function * () {}
]],
['buffer', Buffer.from('🦄')],
['object', [
{x: 1},
Object.create({x: 1})
]],
['regExp', [
/\w/,
new RegExp('\\w')
]],
['date', new Date()],
['error', [
new Error('🦄'),
new ErrorSubclassFixture()
]],
['nativePromise', [
Promise.resolve(),
PromiseSubclassFixture.resolve()
]],
['promise', {then() {}, catch() {}}],
['generator', (function * () {
yield 4;
})()],
['generatorFunction', function * () {
yield 4;
}],
['map', new Map()],
['set', new Set()],
['weakMap', new WeakMap()],
['int8Array', new Int8Array()],
['uint8Array', new Uint8Array()],
['uint8ClampedArray', new Uint8ClampedArray()],
['uint16Array', new Uint16Array()],
['int32Array', new Int32Array()],
['uint32Array', new Uint32Array()],
['float32Array', new Float32Array()],
['float64Array', new Float64Array()],
['arrayBuffer', new ArrayBuffer(10)],
['nan', [
NaN,
Number.NaN
]],
['nullOrUndefined', [
null,
undefined
]],
['plainObject', [
{x: 1},
Object.create(null),
new Object() // eslint-disable-line no-new-object
]],
['integer', 6]
]);
// This ensures a certain method matches only the types
// it's supposed to and none of the other methods' types
const testType = (t, type, exclude) => {
for (const [key, value] of types) {
// TODO: Automatically exclude value types in other tests that we have in the current one.
// Could reduce the use of `exclude`.
if (exclude && exclude.indexOf(key) !== -1) {
continue;
}
const assert = key === type ? t.true.bind(t) : t.false.bind(t);
const is = m[type];
const fixtures = Array.isArray(value) ? value : [value];
for (const fixture of fixtures) {
assert(is(fixture), `Value: ${util.inspect(fixture)}`);
}
}
};
test('is.undefined', t => {
testType(t, 'undefined', ['nullOrUndefined']);
});
test('is.null', t => {
testType(t, 'null', ['nullOrUndefined']);
});
test('is.string', t => {
testType(t, 'string');
});
test('is.number', t => {
testType(t, 'number', ['nan', 'integer']);
});
test('is.boolean', t => {
testType(t, 'boolean');
});
test('is.symbol', t => {
testType(t, 'symbol');
});
test('is.array', t => {
testType(t, 'array');
});
test('is.function', t => {
testType(t, 'function', ['generatorFunction']);
});
test('is.buffer', t => {
testType(t, 'buffer');
});
test('is.object', t => {
for (const el of types.get('object')) {
t.true(m.object(el));
}
});
test('is.regExp', t => {
testType(t, 'regExp');
});
test('is.date', t => {
testType(t, 'date');
});
test('is.error', t => {
testType(t, 'error');
});
if (isNode8orHigher) {
test('is.nativePromise', t => {
testType(t, 'nativePromise');
});
test('is.promise', t => {
testType(t, 'promise', ['nativePromise']);
});
}
test('is.generator', t => {
testType(t, 'generator');
});
test('is.generatorFunction', t => {
testType(t, 'generatorFunction', ['function']);
});
test('is.map', t => {
testType(t, 'map');
});
test('is.set', t => {
testType(t, 'set');
});
test('is.weakMap', t => {
testType(t, 'weakMap');
});
test('is.weakSet', t => {
testType(t, 'weakSet');
});
test('is.int8Array', t => {
testType(t, 'int8Array');
});
test('is.uint8Array', t => {
testType(t, 'uint8Array', ['buffer']);
});
test('is.uint8ClampedArray', t => {
testType(t, 'uint8ClampedArray');
});
test('is.int16Array', t => {
testType(t, 'int16Array');
});
test('is.uint16Array', t => {
testType(t, 'uint16Array');
});
test('is.int32Array', t => {
testType(t, 'int32Array');
});
test('is.uint32Array', t => {
testType(t, 'uint32Array');
});
test('is.float32Array', t => {
testType(t, 'float32Array');
});
test('is.float64Array', t => {
testType(t, 'float64Array');
});
test('is.arrayBuffer', t => {
testType(t, 'arrayBuffer');
});
test('is.dataView', t => {
testType(t, 'arrayBuffer');
});
test('is.nan', t => {
testType(t, 'nan');
});
test('is.nullOrUndefined', t => {
testType(t, 'nullOrUndefined', ['undefined', 'null']);
});
test('is.primitive', t => {
const primitives = [
undefined,
null,
'🦄',
6,
Infinity,
-Infinity,
true,
false,
Symbol('🦄')
];
for (const el of primitives) {
t.true(m.primitive(el));
}
});
test('is.integer', t => {
testType(t, 'integer', ['number']);
t.false(m.integer(1.4));
});
test('is.plainObject', t => {
testType(t, 'plainObject', ['object', 'promise']);
});
test('is.iterable', t => {
t.true(m.iterable(''));
t.true(m.iterable([]));
t.true(m.iterable(new Map()));
t.false(m.iterable(null));
t.false(m.iterable(undefined));
t.false(m.iterable(0));
t.false(m.iterable(NaN));
t.false(m.iterable(Infinity));
t.false(m.iterable({}));
});
test('is.class', t => {
class Foo {}
const classDeclarations = [
Foo,
class Bar extends Foo {}
];
for (const x of classDeclarations) {
t.true(m.class(x));
}
});
test('is.typedArray', t => {
const typedArrays = [
new Int8Array(),
new Uint8Array(),
new Uint8ClampedArray(),
new Uint16Array(),
new Int32Array(),
new Uint32Array(),
new Float32Array(),
new Float64Array()
];
for (const el of typedArrays) {
t.true(m.typedArray(el));
}
t.false(m.typedArray(new ArrayBuffer(1)));
t.false(m.typedArray([]));
t.false(m.typedArray({}));
});
test('is.inRange', t => {
const x = 3;
t.true(m.inRange(x, [0, 5]));
t.true(m.inRange(x, [5, 0]));
t.true(m.inRange(x, [-5, 5]));
t.true(m.inRange(x, [5, -5]));
t.false(m.inRange(x, [4, 8]));
t.true(m.inRange(-7, [-5, -10]));
t.true(m.inRange(-5, [-5, -10]));
t.true(m.inRange(-10, [-5, -10]));
t.true(m.inRange(x, 10));
t.true(m.inRange(0, 0));
t.true(m.inRange(-2, -3));
t.false(m.inRange(x, 2));
t.false(m.inRange(-3, -2));
t.throws(() => {
m.inRange(0);
});
t.throws(() => {
m.inRange(0, []);
});
t.throws(() => {
m.inRange(0, [5]);
});
t.throws(() => {
m.inRange(0, [1, 2, 3]);
});
});

2822
test/test.ts Normal file

File diff suppressed because it is too large Load diff

12
test/tsconfig.json Normal file
View file

@ -0,0 +1,12 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "..",
"noUnusedLocals": false,
"noUnusedParameters": false
},
"include": [
"../source",
"type-tests.ts"
]
}

405
test/type-tests.ts Normal file
View file

@ -0,0 +1,405 @@
import {expectTypeOf} from 'expect-type';
import is, {
assert as isAssert,
assertNotNullOrUndefined,
assertNotPrimitive,
assertNotString,
assertNotUndefined,
type EvenInteger,
type FiniteNumber,
type Integer,
type NaN as NaNType,
type NegativeInfinity,
type NegativeInteger,
type NegativeNumber,
type NonNegativeInteger,
type NonNegativeNumber,
type OddInteger,
type PositiveInfinity,
type PositiveInteger,
type PositiveNumber,
type Primitive,
type SafeInteger,
type ValidLength,
} from '../source/index.ts';
// eslint-disable-next-line @typescript-eslint/no-restricted-types
type UnknownNotPrimitive<Forbidden extends Primitive> = Exclude<Primitive, Forbidden> | object;
// For each predicate, verify two things:
// 1. True branch narrows to the branded type.
// 2. False branch on a `number` input stays `number` (not `never`).
// Without the branded types, `Exclude<number, number>` = `never` would break
// the common validation-guard pattern: if (!is.X(n)) throw; use(n).
const nanCheck = (value: number) => {
if (is.nan(value)) {
const _: NaNType = value;
} else {
const _: number = value;
}
};
const finiteNumberCheck = (value: number) => {
if (is.finiteNumber(value)) {
const _: FiniteNumber = value;
} else {
const _: number = value;
}
};
const nonNegativeNumberCheck = (value: number) => {
if (is.nonNegativeNumber(value)) {
const _: NonNegativeNumber = value;
} else {
const _: number = value;
}
};
const positiveIntegerCheck = (value: number) => {
if (is.positiveInteger(value)) {
const _: PositiveInteger = value;
const __: Integer = value;
const ___: NonNegativeInteger = value;
} else {
const _: number = value;
}
};
const negativeIntegerCheck = (value: number) => {
if (is.negativeInteger(value)) {
const _: NegativeInteger = value;
const __: Integer = value;
} else {
const _: number = value;
}
};
const nonNegativeIntegerCheck = (value: number) => {
if (is.nonNegativeInteger(value)) {
const _: NonNegativeInteger = value;
const __: Integer = value;
} else {
const _: number = value;
}
};
const infiniteCheck = (value: number) => {
if (is.infinite(value)) {
const _: PositiveInfinity | NegativeInfinity = value;
const __: PositiveNumber | NegativeNumber = value;
} else {
const _: number = value;
}
};
const integerCheck = (value: number) => {
if (is.integer(value)) {
const _: Integer = value;
const __: FiniteNumber = value;
} else {
const _: number = value;
}
};
const safeIntegerCheck = (value: number) => {
if (is.safeInteger(value)) {
const _: SafeInteger = value;
const __: Integer = value;
} else {
const _: number = value;
}
};
const evenIntegerCheck = (value: number) => {
if (is.evenInteger(value)) {
const _: EvenInteger = value;
const __: Integer = value;
} else {
const _: number = value;
}
};
const oddIntegerCheck = (value: number) => {
if (is.oddInteger(value)) {
const _: OddInteger = value;
const __: Integer = value;
} else {
const _: number = value;
}
};
const positiveNumberCheck = (value: number) => {
if (is.positiveNumber(value)) {
const _: PositiveNumber = value;
const __: NonNegativeNumber = value;
} else {
const _: number = value;
}
};
const negativeNumberCheck = (value: number) => {
if (is.negativeNumber(value)) {
const _: NegativeNumber = value;
} else {
const _: number = value;
}
};
const validLengthCheck = (value: number) => {
if (is.validLength(value)) {
const _: ValidLength = value;
const __: SafeInteger = value;
const ___: NonNegativeInteger = value;
} else {
const _: number = value;
}
};
const integerUnknownCheck = (value: unknown) => {
if (is.integer(value)) {
const _: Integer = value;
const __: FiniteNumber = value;
}
};
const positiveIntegerUnknownCheck = (value: unknown) => {
if (is.positiveInteger(value)) {
const _: PositiveInteger = value;
const __: NonNegativeInteger = value;
}
};
const integerMixedUnionCheck = (value: string | number) => {
if (is.integer(value)) {
const _: number = value;
} else {
const _: string = value;
}
};
const positiveNumberMixedUnionCheck = (value: string | number) => {
if (is.positiveNumber(value)) {
const _: number = value;
} else {
const _: string = value;
}
};
const chainedNumericGuardCheck = (value: number) => {
if (is.positiveNumber(value) && is.integer(value)) {
const _: PositiveNumber = value;
const __: Integer = value;
const ___: FiniteNumber = value;
}
};
const distinctNumericBrandsStayDistinct = (
positiveInteger: PositiveInteger,
negativeInteger: NegativeInteger,
validLength: ValidLength,
) => {
// @ts-expect-error -- Distinct numeric refinements must not collapse into each other.
const _: NegativeInteger = positiveInteger;
// @ts-expect-error -- ValidLength is non-negative and must not become a signed integer refinement.
const __: NegativeInteger = validLength;
return negativeInteger;
};
const assertNotUndefinedCheck = (value: string | undefined) => {
isAssert.not.undefined(value);
expectTypeOf(value).toEqualTypeOf<string>();
};
const assertNotUndefinedUnknownCheck = (value: unknown) => {
isAssert.not.undefined(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<undefined>>();
};
const assertNotUndefinedGenericCheck = <T>(value: T) => {
isAssert.not.undefined(value);
const _: Exclude<T, undefined> = value;
};
const nullValue = null;
type Null = typeof nullValue;
const assertNotNullUnknownCheck = (value: unknown) => {
isAssert.not.null(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<Null>>();
};
const assertNotNullOrUndefinedCheck = (value: string | Null | undefined) => {
isAssert.not.nullOrUndefined(value);
expectTypeOf(value).toEqualTypeOf<string>();
};
const assertNotNullOrUndefinedUnknownCheck = (value: unknown) => {
isAssert.not.nullOrUndefined(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<Null | undefined>>();
};
const assertNotStringCheck = (value: string | number) => {
isAssert.not.string(value);
expectTypeOf(value).toEqualTypeOf<number>();
};
const assertNotStringUnknownCheck = (value: unknown) => {
isAssert.not.string(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<string>>();
};
const assertNotStringGenericCheck = <T>(value: T) => {
isAssert.not.string(value);
const _: Exclude<T, string> = value;
};
const assertNotBooleanUnknownCheck = (value: unknown) => {
isAssert.not.boolean(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<boolean>>();
};
const assertNotSymbolUnknownCheck = (value: unknown) => {
isAssert.not.symbol(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<symbol>>();
};
const assertNotBigintUnknownCheck = (value: unknown) => {
isAssert.not.bigint(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<bigint>>();
};
const assertNotPrimitiveUnknownCheck = (value: unknown) => {
isAssert.not.primitive(value);
// eslint-disable-next-line @typescript-eslint/no-restricted-types
expectTypeOf(value).toEqualTypeOf<object>();
};
const assertNotPrimitiveGenericCheck = <T>(value: T) => {
isAssert.not.primitive(value);
const _: Exclude<T, Primitive> = value;
};
const assertNotNamedUndefinedExportCheck = (value: 0 | false | '' | Null | undefined | 'ok') => {
assertNotUndefined(value);
expectTypeOf(value).toEqualTypeOf<0 | false | '' | Null | 'ok'>();
};
const assertNotNamedNullOrUndefinedUnknownExportCheck = (value: unknown) => {
assertNotNullOrUndefined(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<Null | undefined>>();
};
const assertNotNamedStringExportCheck = (value: string | number) => {
assertNotString(value);
expectTypeOf(value).toEqualTypeOf<number>();
};
const assertNotNamedStringUnknownExportCheck = (value: unknown) => {
assertNotString(value);
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<string>>();
};
const assertNotNamedPrimitiveUnknownExportCheck = (value: unknown) => {
assertNotPrimitive(value);
// eslint-disable-next-line @typescript-eslint/no-restricted-types
expectTypeOf(value).toEqualTypeOf<object>();
};
const assertNotCallableDoesNotExistCheck = (value: string | undefined) => {
// @ts-expect-error -- Generic negative assertions cannot safely infer complement types from arbitrary predicates.
isAssert.not(is.undefined, value);
const _: string | undefined = value;
};
const assertNotNumberDoesNotExistCheck = (value: string | number) => {
// @ts-expect-error -- `is.number` rejects `NaN`, so a narrowing negative assertion would be unsound.
isAssert.not.number(value); // eslint-disable-line @typescript-eslint/no-unsafe-call
const _: string | number = value;
};
const assertNotIntegerDoesNotExistCheck = (value: string | number) => {
// @ts-expect-error -- Numeric refinements are intentionally excluded from `assert.not`.
isAssert.not.integer(value); // eslint-disable-line @typescript-eslint/no-unsafe-call
const _: string | number = value;
};
const assertNotObjectDoesNotExistCheck = (value: Record<string, unknown> | string) => {
// @ts-expect-error -- TypeScript's `{}` type includes primitives, so `not.object` cannot safely narrow every object-like input.
isAssert.not.object(value); // eslint-disable-line @typescript-eslint/no-unsafe-call
const _: Record<string, unknown> | string = value;
};
const assertNotBlobDoesNotExistCheck = (value: Blob | File | string) => {
// @ts-expect-error -- `File` extends `Blob` in TypeScript but does not match the exact runtime `Blob` check.
isAssert.not.blob(value); // eslint-disable-line @typescript-eslint/no-unsafe-call
const _: Blob | File | string = value;
};
const assertNotMapDoesNotExistCheck = (value: Map<string, number> | string) => {
// @ts-expect-error -- Structural object types such as `Map` can be assignable in TypeScript without matching the runtime brand check.
isAssert.not.map(value); // eslint-disable-line @typescript-eslint/no-unsafe-call, unicorn/no-array-callback-reference
const _: Map<string, number> | string = value;
};
const assertNotSetDoesNotExistCheck = (value: Set<string> | string) => {
// @ts-expect-error -- Structural object types such as `Set` can be assignable in TypeScript without matching the runtime brand check.
isAssert.not.set(value); // eslint-disable-line @typescript-eslint/no-unsafe-call
const _: Set<string> | string = value;
};
const assertNotDateDoesNotExistCheck = (value: Date | string) => {
// @ts-expect-error -- Structural object types such as `Date` can be assignable in TypeScript without matching the runtime brand check.
isAssert.not.date(value); // eslint-disable-line @typescript-eslint/no-unsafe-call
const _: Date | string = value;
};
// Suppress unused variable warnings
nanCheck(42);
finiteNumberCheck(42);
nonNegativeNumberCheck(42);
positiveIntegerCheck(42);
negativeIntegerCheck(-1);
nonNegativeIntegerCheck(0);
infiniteCheck(Number.POSITIVE_INFINITY);
integerCheck(1);
safeIntegerCheck(1);
evenIntegerCheck(2);
oddIntegerCheck(1);
positiveNumberCheck(1);
negativeNumberCheck(-1);
validLengthCheck(0);
integerUnknownCheck(1);
positiveIntegerUnknownCheck(1);
integerMixedUnionCheck(1);
positiveNumberMixedUnionCheck(1);
chainedNumericGuardCheck(1);
distinctNumericBrandsStayDistinct(42 as PositiveInteger, -1 as NegativeInteger, 0 as ValidLength);
assertNotUndefinedCheck('🦄');
assertNotUndefinedUnknownCheck('🦄');
assertNotUndefinedGenericCheck<string | undefined>('🦄');
assertNotNullUnknownCheck('🦄');
assertNotNullOrUndefinedCheck('🦄');
assertNotNullOrUndefinedUnknownCheck('🦄');
assertNotStringCheck(1);
assertNotStringUnknownCheck(1);
assertNotStringGenericCheck<string | number>(1);
assertNotBooleanUnknownCheck(1);
assertNotSymbolUnknownCheck(1);
assertNotBigintUnknownCheck(1);
assertNotPrimitiveUnknownCheck({});
assertNotPrimitiveGenericCheck<string | {unicorn: true}>({unicorn: true});
assertNotNamedUndefinedExportCheck(0);
assertNotNamedNullOrUndefinedUnknownExportCheck('🦄');
assertNotNamedStringExportCheck(1);
assertNotNamedStringUnknownExportCheck(1);
assertNotNamedPrimitiveUnknownExportCheck({});
assertNotCallableDoesNotExistCheck('🦄');
assertNotNumberDoesNotExistCheck(Number.NaN);
assertNotIntegerDoesNotExistCheck(1.5);
assertNotObjectDoesNotExistCheck('🦄');
assertNotBlobDoesNotExistCheck('🦄');
assertNotMapDoesNotExistCheck('🦄');
assertNotSetDoesNotExistCheck('🦄');
assertNotDateDoesNotExistCheck('🦄');

12
tsconfig.json Normal file
View file

@ -0,0 +1,12 @@
{
"extends": "@sindresorhus/tsconfig",
"compilerOptions": {
"types": ["node"],
"rootDir": "source",
"allowImportingTsExtensions": true,
"rewriteRelativeImportExtensions": true
},
"include": [
"source"
],
}