diff --git a/index.js b/index.js index 2ba0ab3..5734148 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,10 @@ '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 @@ -29,7 +33,7 @@ const is = value => { return 'symbol'; } - if (type === 'function') { + if (is.function(value)) { return 'Function'; } @@ -53,74 +57,63 @@ const is = value => { return 'Object'; }; -is.undefined = x => typeof x === 'undefined'; +is.undefined = isOfType('undefined'); is.null = x => x === null; -is.string = x => typeof x === 'string'; -is.number = x => typeof x === 'number'; -is.boolean = x => typeof x === 'boolean'; -is.symbol = x => typeof x === 'symbol'; +is.string = isOfType('string'); +is.number = isOfType('number'); +is.boolean = isOfType('boolean'); +is.symbol = isOfType('symbol'); is.array = Array.isArray; -is.function = x => typeof x === 'function'; +is.function = isOfType('function'); is.buffer = Buffer.isBuffer; -is.object = x => { - const type = typeof x; - return x !== null && (type === 'object' || type === 'function'); -}; +const isObject = x => typeof x === 'object'; -is.nativePromise = x => getObjectType(x) === 'Promise'; +is.object = x => !is.nullOrUndefined(x) && (is.function(x) || isObject(x)); -is.promise = x => { - return is.nativePromise(x) || - ( - x !== null && - typeof x === 'object' && - typeof x.then === 'function' && - typeof x.catch === 'function' - ); -}; +is.nativePromise = isObjectOfType('Promise'); -is.regExp = x => getObjectType(x) === 'RegExp'; -is.date = x => getObjectType(x) === 'Date'; -is.error = x => getObjectType(x) === 'Error'; -is.map = x => getObjectType(x) === 'Map'; -is.set = x => getObjectType(x) === 'Set'; -is.weakMap = x => getObjectType(x) === 'WeakMap'; -is.weakSet = x => getObjectType(x) === 'WeakSet'; +const hasPromiseAPI = x => + !is.null(x) && + isObject(x) && + is.function(x.then) && + is.function(x.catch); -is.int8Array = x => getObjectType(x) === 'Int8Array'; -is.uint8Array = x => getObjectType(x) === 'Uint8Array'; -is.uint8ClampedArray = x => getObjectType(x) === 'Uint8ClampedArray'; -is.int16Array = x => getObjectType(x) === 'Int16Array'; -is.uint16Array = x => getObjectType(x) === 'Uint16Array'; -is.int32Array = x => getObjectType(x) === 'Int32Array'; -is.uint32Array = x => getObjectType(x) === 'Uint32Array'; -is.float32Array = x => getObjectType(x) === 'Float32Array'; -is.float64Array = x => getObjectType(x) === 'Float64Array'; +is.promise = x => is.nativePromise(x) || hasPromiseAPI(x); -is.arrayBuffer = x => getObjectType(x) === 'ArrayBuffer'; +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.sharedArrayBuffer = x => { - try { - return getObjectType(x) === 'SharedArrayBuffer'; - } catch (err) { - return false; - } -}; +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 => x === null || typeof x === 'undefined'; +is.nullOrUndefined = x => is.null(x) || is.undefined(x); -is.primitive = x => { - const type = typeof x; - return x === null || - type === 'undefined' || - type === 'string' || - type === 'number' || - type === 'boolean' || - type === 'symbol'; -}; +const primitiveTypes = new Set([ + 'undefined', + 'string', + 'number', + 'boolean', + 'symbol' +]); +is.primitive = x => is.null(x) || primitiveTypes.has(typeof x); is.integer = Number.isInteger; @@ -133,9 +126,9 @@ is.plainObject = x => { prototype === Object.getPrototypeOf({})); }; -is.iterable = x => !is.null(x) && !is.undefined(x) && typeof x[Symbol.iterator] === 'function'; +is.iterable = x => !is.nullOrUndefined(x) && is.function(x[Symbol.iterator]); -is.class = x => typeof x === 'function' && x.toString().startsWith('class '); +is.class = x => is.function(x) && x.toString().startsWith('class '); const typedArrayTypes = new Set([ 'Int8Array', @@ -160,7 +153,7 @@ is.inRange = (x, range) => { return x >= Math.min.apply(null, range) && x <= Math.max.apply(null, range); } - throw new TypeError('Invalid range'); + throw new TypeError(`Invalid range: ${util.inspect}`); }; module.exports = is; diff --git a/test.js b/test.js index 18f6158..316bb41 100644 --- a/test.js +++ b/test.js @@ -10,7 +10,11 @@ const ErrorSubclassFixture = class extends Error {}; const types = new Map([ ['undefined', undefined], ['null', null], - ['string', '🦄'], + ['string', [ + '🦄', + 'hello world', + '' + ]], ['number', [ 6, 1.4, @@ -320,13 +324,23 @@ test('is.inRange', t => { 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(() => { - t.true(m.inRange(0)); + m.inRange(0); }); t.throws(() => { - t.true(m.inRange(0, [5])); + m.inRange(0, []); + }); + + t.throws(() => { + m.inRange(0, [5]); + }); + + t.throws(() => { + m.inRange(0, [1, 2, 3]); }); });