UNPKG

19.3 kBMarkdownView Raw
1# is
2
3> Type check values
4
5For example, `is.string('🦄') //=> true`
6
7<img src="header.gif" width="182" align="right">
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
21npm install @sindresorhus/is
22```
23
24## Usage
25
26```js
27import is from '@sindresorhus/is';
28
29is('🦄');
30//=> 'string'
31
32is(new Map());
33//=> 'Map'
34
35is.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
42import {assert} from '@sindresorhus/is';
43
44assert.string(2);
45//=> Error: Expected value which is `string`, received value of type `number`.
46```
47
48Assertions (except `assertAll` and `assertAny`) also support an optional custom error message.
49
50```js
51import {assert} from '@sindresorhus/is';
52
53assert.nonEmptyString(process.env.API_URL, 'The API_URL environment variable is required.');
54//=> Error: The API_URL environment variable is required.
55```
56
57And with TypeScript:
58
59```ts
60import {assert} from '@sindresorhus/is';
61
62assert.string(foo);
63// `foo` is now typed as a `string`.
64```
65
66### Named exports
67
68Named exports allow tooling to perform tree-shaking, potentially reducing bundle size by including only code from the methods that are used.
69
70Every method listed below is available as a named export. Each method is prefixed by either `is` or `assert` depending on usage.
71
72For example:
73
74```js
75import {assertNull, isUndefined} from '@sindresorhus/is';
76```
77
78## API
79
80### is(value)
81
82Returns the type of `value`.
83
84Primitives are lowercase and object types are camelcase.
85
86Example:
87
88- `'undefined'`
89- `'null'`
90- `'string'`
91- `'symbol'`
92- `'Array'`
93- `'Function'`
94- `'Object'`
95
96This method is also exported as `detect`. You can import it like this:
97
98```js
99import {detect} from '@sindresorhus/is';
100```
101
102Note: 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
106All 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
116Note: `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
126Returns true if `value` is an array and all of its items match the assertion (if provided).
127
128```js
129is.array(value); // Validate `value` is an array.
130is.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##### .blob(value)
137##### .object(value)
138
139Keep in mind that [functions are objects too](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions).
140
141##### .numericString(value)
142
143Returns `true` for a string that represents a number satisfying `is.number`, for example, `'42'` and `'-8.3'`.
144
145Note: `'NaN'` returns `false`, but `'Infinity'` and `'-Infinity'` return `true`.
146
147##### .regExp(value)
148##### .date(value)
149##### .error(value)
150##### .nativePromise(value)
151##### .promise(value)
152
153Returns `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.
154
155##### .generator(value)
156
157Returns `true` for any object that implements its own `.next()` and `.throw()` methods and has a function definition for `Symbol.iterator`.
158
159##### .generatorFunction(value)
160
161##### .asyncFunction(value)
162
163Returns `true` for any `async` function that can be called with the `await` operator.
164
165```js
166is.asyncFunction(async () => {});
167//=> true
168
169is.asyncFunction(() => {});
170//=> false
171```
172
173##### .asyncGenerator(value)
174
175```js
176is.asyncGenerator(
177 (async function * () {
178 yield 4;
179 })()
180);
181//=> true
182
183is.asyncGenerator(
184 (function * () {
185 yield 4;
186 })()
187);
188//=> false
189```
190
191##### .asyncGeneratorFunction(value)
192
193```js
194is.asyncGeneratorFunction(async function * () {
195 yield 4;
196});
197//=> true
198
199is.asyncGeneratorFunction(function * () {
200 yield 4;
201});
202//=> false
203```
204
205##### .boundFunction(value)
206
207Returns `true` for any `bound` function.
208
209```js
210is.boundFunction(() => {});
211//=> true
212
213is.boundFunction(function () {}.bind(null));
214//=> true
215
216is.boundFunction(function () {});
217//=> false
218```
219
220##### .map(value)
221##### .set(value)
222##### .weakMap(value)
223##### .weakSet(value)
224##### .weakRef(value)
225
226#### Typed arrays
227
228##### .int8Array(value)
229##### .uint8Array(value)
230##### .uint8ClampedArray(value)
231##### .int16Array(value)
232##### .uint16Array(value)
233##### .int32Array(value)
234##### .uint32Array(value)
235##### .float32Array(value)
236##### .float64Array(value)
237##### .bigInt64Array(value)
238##### .bigUint64Array(value)
239
240#### Structured data
241
242##### .arrayBuffer(value)
243##### .sharedArrayBuffer(value)
244##### .dataView(value)
245
246##### .enumCase(value, enum)
247
248TypeScript-only. Returns `true` if `value` is a member of `enum`.
249
250```ts
251enum Direction {
252 Ascending = 'ascending',
253 Descending = 'descending'
254}
255
256is.enumCase('ascending', Direction);
257//=> true
258
259is.enumCase('other', Direction);
260//=> false
261```
262
263#### Emptiness
264
265##### .emptyString(value)
266
267Returns `true` if the value is a `string` and the `.length` is 0.
268
269##### .emptyStringOrWhitespace(value)
270
271Returns `true` if `is.emptyString(value)` or if it's a `string` that is all whitespace.
272
273##### .nonEmptyString(value)
274
275Returns `true` if the value is a `string` and the `.length` is more than 0.
276
277##### .nonEmptyStringAndNotWhitespace(value)
278
279Returns `true` if the value is a `string` that is not empty and not whitespace.
280
281```js
282const values = ['property1', '', null, 'property2', ' ', undefined];
283
284values.filter(is.nonEmptyStringAndNotWhitespace);
285//=> ['property1', 'property2']
286```
287
288##### .emptyArray(value)
289
290Returns `true` if the value is an `Array` and the `.length` is 0.
291
292##### .nonEmptyArray(value)
293
294Returns `true` if the value is an `Array` and the `.length` is more than 0.
295
296##### .emptyObject(value)
297
298Returns `true` if the value is an `Object` and `Object.keys(value).length` is 0.
299
300Please note that `Object.keys` returns only own enumerable properties. Hence something like this can happen:
301
302```js
303const object1 = {};
304
305Object.defineProperty(object1, 'property1', {
306 value: 42,
307 writable: true,
308 enumerable: false,
309 configurable: true
310});
311
312is.emptyObject(object1);
313//=> true
314```
315
316##### .nonEmptyObject(value)
317
318Returns `true` if the value is an `Object` and `Object.keys(value).length` is more than 0.
319
320##### .emptySet(value)
321
322Returns `true` if the value is a `Set` and the `.size` is 0.
323
324##### .nonEmptySet(Value)
325
326Returns `true` if the value is a `Set` and the `.size` is more than 0.
327
328##### .emptyMap(value)
329
330Returns `true` if the value is a `Map` and the `.size` is 0.
331
332##### .nonEmptyMap(value)
333
334Returns `true` if the value is a `Map` and the `.size` is more than 0.
335
336#### Miscellaneous
337
338##### .directInstanceOf(value, class)
339
340Returns `true` if `value` is a direct instance of `class`.
341
342```js
343is.directInstanceOf(new Error(), Error);
344//=> true
345
346class UnicornError extends Error {}
347
348is.directInstanceOf(new UnicornError(), Error);
349//=> false
350```
351
352##### .urlInstance(value)
353
354Returns `true` if `value` is an instance of the [`URL` class](https://developer.mozilla.org/en-US/docs/Web/API/URL).
355
356```js
357const url = new URL('https://example.com');
358
359is.urlInstance(url);
360//=> true
361```
362
363##### .urlString(value)
364
365Returns `true` if `value` is a URL string.
366
367Note: this only does basic checking using the [`URL` class](https://developer.mozilla.org/en-US/docs/Web/API/URL) constructor.
368
369```js
370const url = 'https://example.com';
371
372is.urlString(url);
373//=> true
374
375is.urlString(new URL(url));
376//=> false
377```
378
379##### .truthy(value)
380
381Returns `true` for all values that evaluate to true in a boolean context:
382
383```js
384is.truthy('🦄');
385//=> true
386
387is.truthy(undefined);
388//=> false
389```
390
391##### .falsy(value)
392
393Returns `true` if `value` is one of: `false`, `0`, `''`, `null`, `undefined`, `NaN`.
394
395##### .nan(value)
396##### .nullOrUndefined(value)
397##### .primitive(value)
398
399JavaScript primitives are as follows:
400
401- `null`
402- `undefined`
403- `string`
404- `number`
405- `boolean`
406- `symbol`
407- `bigint`
408
409##### .integer(value)
410
411##### .safeInteger(value)
412
413Returns `true` if `value` is a [safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger).
414
415##### .plainObject(value)
416
417An object is plain if it's created by either `{}`, `new Object()`, or `Object.create(null)`.
418
419##### .iterable(value)
420##### .asyncIterable(value)
421##### .class(value)
422
423Returns `true` if the value is a class constructor.
424
425##### .typedArray(value)
426
427##### .arrayLike(value)
428
429A `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.
430
431```js
432is.arrayLike(document.forms);
433//=> true
434
435function foo() {
436 is.arrayLike(arguments);
437 //=> true
438}
439foo();
440```
441
442##### .tupleLike(value, guards)
443
444A `value` is tuple-like if it matches the provided `guards` array both in `.length` and in types.
445
446```js
447is.tupleLike([1], [is.number]);
448//=> true
449```
450
451```js
452function foo() {
453 const tuple = [1, '2', true];
454 if (is.tupleLike(tuple, [is.number, is.string, is.boolean])) {
455 tuple // [number, string, boolean]
456 }
457}
458
459foo();
460```
461
462##### .positiveNumber(value)
463
464Check if `value` is a number and is more than 0.
465
466##### .negativeNumber(value)
467
468Check if `value` is a number and is less than 0.
469
470##### .inRange(value, range)
471
472Check 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.
473
474```js
475is.inRange(3, [0, 5]);
476is.inRange(3, [5, 0]);
477is.inRange(0, [-2, 2]);
478```
479
480##### .inRange(value, upperBound)
481
482Check if `value` (number) is in the range of `0` to `upperBound`.
483
484```js
485is.inRange(3, 10);
486```
487
488##### .htmlElement(value)
489
490Returns `true` if `value` is an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement).
491
492##### .nodeStream(value)
493
494Returns `true` if `value` is a Node.js [stream](https://nodejs.org/api/stream.html).
495
496```js
497import fs from 'node:fs';
498
499is.nodeStream(fs.createReadStream('unicorn.png'));
500//=> true
501```
502
503##### .observable(value)
504
505Returns `true` if `value` is an `Observable`.
506
507```js
508import {Observable} from 'rxjs';
509
510is.observable(new Observable());
511//=> true
512```
513
514##### .infinite(value)
515
516Check if `value` is `Infinity` or `-Infinity`.
517
518##### .evenInteger(value)
519
520Returns `true` if `value` is an even integer.
521
522##### .oddInteger(value)
523
524Returns `true` if `value` is an odd integer.
525
526##### .propertyKey(value)
527
528Returns `true` if `value` can be used as an object property key (either `string`, `number`, or `symbol`).
529
530##### .formData(value)
531
532Returns `true` if `value` is an instance of the [`FormData` class](https://developer.mozilla.org/en-US/docs/Web/API/FormData).
533
534```js
535const data = new FormData();
536
537is.formData(data);
538//=> true
539```
540
541##### .urlSearchParams(value)
542
543Returns `true` if `value` is an instance of the [`URLSearchParams` class](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams).
544
545```js
546const searchParams = new URLSearchParams();
547
548is.urlSearchParams(searchParams);
549//=> true
550```
551
552##### .any(predicate | predicate[], ...values)
553
554Using a single `predicate` argument, returns `true` if **any** of the input `values` returns true in the `predicate`:
555
556```js
557is.any(is.string, {}, true, '🦄');
558//=> true
559
560is.any(is.boolean, 'unicorns', [], new Map());
561//=> false
562```
563
564Using an array of `predicate[]`, returns `true` if **any** of the input `values` returns true for **any** of the `predicates` provided in an array:
565
566```js
567is.any([is.string, is.number], {}, true, '🦄');
568//=> true
569
570is.any([is.boolean, is.number], 'unicorns', [], new Map());
571//=> false
572```
573
574##### .all(predicate, ...values)
575
576Returns `true` if **all** of the input `values` returns true in the `predicate`:
577
578```js
579is.all(is.object, {}, new Map(), new Set());
580//=> true
581
582is.all(is.string, '🦄', [], 'unicorns');
583//=> false
584```
585
586##### .validDate(value)
587
588Returns `true` if the value is a valid date.
589
590All [`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.
591
592```js
593const valid = new Date('2000-01-01');
594
595is.date(valid);
596//=> true
597valid.getTime();
598//=> 946684800000
599valid.toUTCString();
600//=> 'Sat, 01 Jan 2000 00:00:00 GMT'
601is.validDate(valid);
602//=> true
603
604const invalid = new Date('Not a parsable date string');
605
606is.date(invalid);
607//=> true
608invalid.getTime();
609//=> NaN
610invalid.toUTCString();
611//=> 'Invalid Date'
612is.validDate(invalid);
613//=> false
614```
615
616##### .validLength(value)
617
618Returns `true` if the value is a safe integer that is greater than or equal to zero.
619
620This can be useful to confirm that a value is a valid count of something, ie. 0 or more.
621
622##### .whitespaceString(value)
623
624Returns `true` if the value is a string with only whitespace characters.
625
626## Type guards
627
628When 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.
629
630```ts
631import is from '@sindresorhus/is';
632
633const padLeft = (value: string, padding: string | number) => {
634 if (is.number(padding)) {
635 // `padding` is typed as `number`
636 return Array(padding + 1).join(' ') + value;
637 }
638
639 if (is.string(padding)) {
640 // `padding` is typed as `string`
641 return padding + value;
642 }
643
644 throw new TypeError(`Expected 'padding' to be of type 'string' or 'number', got '${is(padding)}'.`);
645}
646
647padLeft('🦄', 3);
648//=> ' 🦄'
649
650padLeft('🦄', '🌈');
651//=> '🌈🦄'
652```
653
654## Type assertions
655
656The 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.
657
658```ts
659import {assert} from '@sindresorhus/is';
660
661const handleMovieRatingApiResponse = (response: unknown) => {
662 assert.plainObject(response);
663 // `response` is now typed as a plain `object` with `unknown` properties.
664
665 assert.number(response.rating);
666 // `response.rating` is now typed as a `number`.
667
668 assert.string(response.title);
669 // `response.title` is now typed as a `string`.
670
671 return `${response.title} (${response.rating * 10})`;
672};
673
674handleMovieRatingApiResponse({rating: 0.87, title: 'The Matrix'});
675//=> 'The Matrix (8.7)'
676
677// This throws an error.
678handleMovieRatingApiResponse({rating: '🦄'});
679```
680
681## Generic type parameters
682
683The 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.
684
685Use 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`.
686
687```ts
688import {assert} from '@sindresorhus/is';
689
690async function badNumberAssumption(input: unknown) {
691 // Bad assumption about the generic type parameter fools the compile-time type system.
692 assert.promise<number>(input);
693 // `input` is a `Promise` but only assumed to be `Promise<number>`.
694
695 const resolved = await input;
696 // `resolved` is typed as `number` but was not actually checked at runtime.
697
698 // Multiplication will return NaN if the input promise did not actually contain a number.
699 return 2 * resolved;
700}
701
702async function goodNumberAssertion(input: unknown) {
703 assert.promise(input);
704 // `input` is typed as `Promise<unknown>`
705
706 const resolved = await input;
707 // `resolved` is typed as `unknown`
708
709 assert.number(resolved);
710 // `resolved` is typed as `number`
711
712 // Uses runtime checks so only numbers will reach the multiplication.
713 return 2 * resolved;
714}
715
716badNumberAssumption(Promise.resolve('An unexpected string'));
717//=> NaN
718
719// This correctly throws an error because of the unexpected string value.
720goodNumberAssertion(Promise.resolve('An unexpected string'));
721```
722
723## FAQ
724
725### Why yet another type checking module?
726
727There are hundreds of type checking modules on npm, unfortunately, I couldn't find any that fit my needs:
728
729- Includes both type methods and ability to get the type
730- Types of primitives returned as lowercase and object types as camelcase
731- Covers all built-ins
732- Unsurprising behavior
733- Well-maintained
734- Comprehensive test suite
735
736For the ones I found, pick 3 of these.
737
738The 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.
739
740### Why not just use `instanceof` instead of this package?
741
742`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.
743
744## Related
745
746- [ow](https://github.com/sindresorhus/ow) - Function argument validation for humans
747- [is-stream](https://github.com/sindresorhus/is-stream) - Check if something is a Node.js stream
748- [is-observable](https://github.com/sindresorhus/is-observable) - Check if a value is an Observable
749- [file-type](https://github.com/sindresorhus/file-type) - Detect the file type of a Buffer/Uint8Array
750- [is-ip](https://github.com/sindresorhus/is-ip) - Check if a string is an IP address
751- [is-array-sorted](https://github.com/sindresorhus/is-array-sorted) - Check if an Array is sorted
752- [is-error-constructor](https://github.com/sindresorhus/is-error-constructor) - Check if a value is an error constructor
753- [is-empty-iterable](https://github.com/sindresorhus/is-empty-iterable) - Check if an Iterable is empty
754- [is-blob](https://github.com/sindresorhus/is-blob) - Check if a value is a Blob - File-like object of immutable, raw data
755- [has-emoji](https://github.com/sindresorhus/has-emoji) - Check whether a string has any emoji
756
757## Maintainers
758
759- [Sindre Sorhus](https://github.com/sindresorhus)
760- [Giora Guttsait](https://github.com/gioragutt)
761- [Brandon Smith](https://github.com/brandon93s)