UNPKG

typechecker

Version:

Utilities to get and check variable types (isString, isPlainObject, isRegExp, etc)

154 lines (153 loc) 4.79 kB
/* eslint quote-props:0 */ // Prepare const isClassRegex = /^class\s|^function\s+[A-Z]/; const isConventionalClassRegex = /^function\s+[A-Z]/; const isNativeClassRegex = /^class\s/; // ----------------------------------- // Values /** Get the object type string */ export function getObjectType(value) { return Object.prototype.toString.call(value); } export function isObject(value) { // null and undefined are objects, hence the extra check return value != null && typeof value === 'object'; } export function isPlainObject(value) { /* eslint no-proto:0 */ // null and undefined are objects, hence the extra check return value != null && value.__proto__ === Object.prototype; } export function isNativeClass(value) { // NOTE TO DEVELOPER: If any of this changes, isClass must also be updated return (typeof value === 'function' && isNativeClassRegex.test(value.toString())); } export function isConventionalClass(value) { return (typeof value === 'function' && isConventionalClassRegex.test(value.toString())); } export function isClass(value) { return typeof value === 'function' && isClassRegex.test(value.toString()); } export function isError(value) { return value instanceof Error; } export function isDate(value) { return getObjectType(value) === '[object Date]'; } export function isArguments(value) { return getObjectType(value) === '[object Arguments]'; } export function isSyncFunction(value) { return getObjectType(value) === '[object Function]'; } export function isAsyncFunction(value) { return getObjectType(value) === '[object AsyncFunction]'; } export function isFunction(value) { return isSyncFunction(value) || isAsyncFunction(value); } export function isRegExp(value) { return getObjectType(value) === '[object RegExp]'; } export function isArray(value) { return ((typeof Array.isArray === 'function' && Array.isArray(value)) || getObjectType(value) === '[object Array]'); } export function isNumber(value) { return typeof value === 'number' || getObjectType(value) === '[object Number]'; } export function isString(value) { return typeof value === 'string' || getObjectType(value) === '[object String]'; } export function isBoolean(value) { return (value === true || value === false || getObjectType(value) === '[object Boolean]'); } export function isNull(value) { return value === null; } export function isUndefined(value) { return typeof value === 'undefined'; } export function isNullish(value) { return value == null; } export function isMap(value) { return getObjectType(value) === '[object Map]'; } export function isWeakMap(value) { return getObjectType(value) === '[object WeakMap]'; } export function isEmptyArray(value) { if (!isArray(value)) throw new Error('value was not an array'); return value.length === 0; } export function isEmptyPlainObject(value) { if (!isPlainObject(value)) throw new Error('value was not a plain object'); // We could use Object.keys, but this is more efficient for (const key in value) { if (value.hasOwnProperty(key)) { return false; } } return true; } export function isEmptyMap(value) { if (!isMap(value)) throw new Error('value was not a map'); return value.size === 0; } export function isEmptyWeakMap(value) { if (!isWeakMap(value)) throw new Error('value was not a weak map'); return Object.keys(value).length === 0; } export function isEmptyKeys(value) { if (value == null) return false; return Object.keys(value).length === 0; } // ----------------------------------- // General /** * The default {@link TypeMap} for {@link getType}. export * AsyncFunction and SyncFunction are missing, as they are more specific types that people can detect afterwards. * @readonly */ export const typeMap = Object.freeze({ array: isArray, boolean: isBoolean, date: isDate, error: isError, class: isClass, function: isFunction, null: isNull, number: isNumber, regexp: isRegExp, string: isString, undefined: isUndefined, map: isMap, weakmap: isWeakMap, object: isObject, }); /** * Cycle through the passed {@link TypeMap} testing the value, returning the first type that passes, otherwise `null`. * @param value the value to test * @param customTypeMap defaults to {@link typeMap} */ export function getType(value, customTypeMap = typeMap) { // Cycle through our type map for (const key in customTypeMap) { if (customTypeMap.hasOwnProperty(key)) { if (customTypeMap[key](value)) { return key; } } } // No type was successful return null; }