UNPKG

@sindresorhus/is

Version:
1,447 lines 51.5 kB
import { keysOf } from "./utilities.js"; const typedArrayTypeNames = [ 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', ]; function isTypedArrayName(name) { return typedArrayTypeNames.includes(name); } const objectTypeNames = [ 'Function', 'Generator', 'AsyncGenerator', 'GeneratorFunction', 'AsyncGeneratorFunction', 'AsyncFunction', 'Observable', 'Array', 'Buffer', 'Blob', 'Object', 'RegExp', 'Date', 'Error', 'Map', 'Set', 'WeakMap', 'WeakSet', 'WeakRef', 'ArrayBuffer', 'SharedArrayBuffer', 'DataView', 'Promise', 'URL', 'FormData', 'URLSearchParams', 'HTMLElement', 'NaN', ...typedArrayTypeNames, ]; function isObjectTypeName(name) { return objectTypeNames.includes(name); } const primitiveTypeNames = [ 'null', 'undefined', 'string', 'number', 'bigint', 'boolean', 'symbol', ]; function isPrimitiveTypeName(name) { return primitiveTypeNames.includes(name); } const assertionTypeDescriptions = [ 'bound Function', 'positive number', 'negative number', 'Class', 'string with a number', 'null or undefined', 'Iterable', 'AsyncIterable', 'native Promise', 'EnumCase', 'string with a URL', 'truthy', 'falsy', 'primitive', 'integer', 'plain object', 'TypedArray', 'array-like', 'tuple-like', 'Node.js Stream', 'infinite number', 'empty array', 'non-empty array', 'empty string', 'empty string or whitespace', 'non-empty string', 'non-empty string and not whitespace', 'empty object', 'non-empty object', 'empty set', 'non-empty set', 'empty map', 'non-empty map', 'PropertyKey', 'even integer', 'finite number', 'negative integer', 'non-negative integer', 'non-negative number', 'odd integer', 'positive integer', 'safe integer', 'T', 'in range', 'predicate returns truthy for any value', 'predicate returns truthy for all values', 'valid Date', 'valid length', 'whitespace string', ...objectTypeNames, ...primitiveTypeNames, ]; const getObjectType = (value) => { const objectTypeName = Object.prototype.toString.call(value).slice(8, -1); if (/HTML\w+Element/v.test(objectTypeName) && isHtmlElement(value)) { return 'HTMLElement'; } if (isObjectTypeName(objectTypeName)) { return objectTypeName; } return undefined; }; function detect(value) { if (value === null) { return 'null'; } // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (typeof value) { case 'undefined': { return 'undefined'; } case 'string': { return 'string'; } case 'number': { return Number.isNaN(value) ? 'NaN' : 'number'; } case 'boolean': { return 'boolean'; } case 'function': { return 'Function'; } case 'bigint': { return 'bigint'; } case 'symbol': { return 'symbol'; } default: } if (isObservable(value)) { return 'Observable'; } if (isArray(value)) { return 'Array'; } if (isBuffer(value)) { return 'Buffer'; } const tagType = getObjectType(value); if (tagType !== undefined && tagType !== 'Object') { return tagType; } if (hasPromiseApi(value)) { return 'Promise'; } if (isBoxedPrimitiveObject(value)) { throw new TypeError('Please don\'t use object wrappers for primitive types'); } return 'Object'; } function hasPromiseApi(value) { return isFunction(value?.then) && isFunction(value?.catch); } function hasBoxedPrimitiveBrand(value, valueOf) { try { // `Object.prototype.toString` can be spoofed via `Symbol.toStringTag`, but the // boxed primitive `valueOf` methods still enforce the real internal brand. Reflect.apply(valueOf, value, []); return true; } catch { return false; } } function isBoxedPrimitiveObject(value) { return hasBoxedPrimitiveBrand(value, String.prototype.valueOf) || hasBoxedPrimitiveBrand(value, Boolean.prototype.valueOf) || hasBoxedPrimitiveBrand(value, Number.prototype.valueOf); } const is = Object.assign(detect, { all: isAll, any: isAny, array: isArray, arrayBuffer: isArrayBuffer, arrayLike: isArrayLike, arrayOf: isArrayOf, asyncFunction: isAsyncFunction, asyncGenerator: isAsyncGenerator, asyncGeneratorFunction: isAsyncGeneratorFunction, asyncIterable: isAsyncIterable, bigint: isBigint, bigInt64Array: isBigInt64Array, bigUint64Array: isBigUint64Array, blob: isBlob, boolean: isBoolean, boundFunction: isBoundFunction, buffer: isBuffer, class: isClass, dataView: isDataView, date: isDate, detect, directInstanceOf: isDirectInstanceOf, emptyArray: isEmptyArray, emptyMap: isEmptyMap, emptyObject: isEmptyObject, emptySet: isEmptySet, emptyString: isEmptyString, emptyStringOrWhitespace: isEmptyStringOrWhitespace, enumCase: isEnumCase, error: isError, evenInteger: isEvenInteger, falsy: isFalsy, finiteNumber: isFiniteNumber, float32Array: isFloat32Array, float64Array: isFloat64Array, formData: isFormData, function: isFunction, generator: isGenerator, generatorFunction: isGeneratorFunction, htmlElement: isHtmlElement, infinite: isInfinite, inRange: isInRange, int16Array: isInt16Array, int32Array: isInt32Array, int8Array: isInt8Array, integer: isInteger, iterable: isIterable, map: isMap, nan: isNan, nativePromise: isNativePromise, negativeInteger: isNegativeInteger, negativeNumber: isNegativeNumber, nodeStream: isNodeStream, nonEmptyArray: isNonEmptyArray, nonEmptyMap: isNonEmptyMap, nonEmptyObject: isNonEmptyObject, nonEmptySet: isNonEmptySet, nonEmptyString: isNonEmptyString, nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace, nonNegativeInteger: isNonNegativeInteger, nonNegativeNumber: isNonNegativeNumber, null: isNull, nullOrUndefined: isNullOrUndefined, number: isNumber, numericString: isNumericString, object: isObject, observable: isObservable, oddInteger: isOddInteger, oneOf: isOneOf, plainObject: isPlainObject, positiveInteger: isPositiveInteger, positiveNumber: isPositiveNumber, primitive: isPrimitive, promise: isPromise, propertyKey: isPropertyKey, regExp: isRegExp, safeInteger: isSafeInteger, set: isSet, sharedArrayBuffer: isSharedArrayBuffer, string: isString, symbol: isSymbol, truthy: isTruthy, tupleLike: isTupleLike, typedArray: isTypedArray, uint16Array: isUint16Array, uint32Array: isUint32Array, uint8Array: isUint8Array, uint8ClampedArray: isUint8ClampedArray, undefined: isUndefined, urlInstance: isUrlInstance, urlSearchParams: isUrlSearchParams, urlString: isUrlString, optional: isOptional, validDate: isValidDate, validLength: isValidLength, weakMap: isWeakMap, weakRef: isWeakRef, weakSet: isWeakSet, whitespaceString: isWhitespaceString, }); function isAbsoluteModule2(remainder) { return (value) => isInteger(value) && Math.abs(value % 2) === remainder; } function validatePredicateArray(predicateArray, allowEmpty) { if (predicateArray.length === 0) { if (allowEmpty) { // Next major release: throw for empty predicate arrays to avoid vacuous results. // throw new TypeError('Invalid predicate array'); } else { throw new TypeError('Invalid predicate array'); } return; } for (const predicate of predicateArray) { validatePredicate(predicate); } } function validatePredicate(predicate) { if (!isFunction(predicate)) { throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); } } export function isAll(predicate, ...values) { if (Array.isArray(predicate)) { const predicateArray = predicate; validatePredicateArray(predicateArray, values.length === 0); const combinedPredicate = (value) => predicateArray.every(singlePredicate => singlePredicate(value)); if (values.length === 0) { return combinedPredicate; } return predicateOnArray(Array.prototype.every, combinedPredicate, values); } return predicateOnArray(Array.prototype.every, predicate, values); } export function isAny(predicate, ...values) { if (Array.isArray(predicate)) { const predicateArray = predicate; validatePredicateArray(predicateArray, values.length === 0); const combinedPredicate = (value) => predicateArray.some(singlePredicate => singlePredicate(value)); if (values.length === 0) { return combinedPredicate; } return predicateOnArray(Array.prototype.some, combinedPredicate, values); } return predicateOnArray(Array.prototype.some, predicate, values); } export function isOptional(value, predicate) { return isUndefined(value) || predicate(value); } export function isArray(value, assertion) { if (!Array.isArray(value)) { return false; } if (!isFunction(assertion)) { return true; } // eslint-disable-next-line @typescript-eslint/no-unsafe-argument return value.every(element => assertion(element)); } export function isArrayBuffer(value) { return getObjectType(value) === 'ArrayBuffer'; } export function isArrayLike(value) { return !isNullOrUndefined(value) && !isFunction(value) && isValidLength(value.length); } export function isArrayOf(predicate) { return (value) => isArray(value) && value.every(element => predicate(element)); } export function isAsyncFunction(value) { return getObjectType(value) === 'AsyncFunction'; } export function isAsyncGenerator(value) { return isAsyncIterable(value) && isFunction(value.next) && isFunction(value.throw); } export function isAsyncGeneratorFunction(value) { return getObjectType(value) === 'AsyncGeneratorFunction'; } export function isAsyncIterable(value) { return isFunction(value?.[Symbol.asyncIterator]); } export function isBigint(value) { return typeof value === 'bigint'; } export function isBigInt64Array(value) { return getObjectType(value) === 'BigInt64Array'; } export function isBigUint64Array(value) { return getObjectType(value) === 'BigUint64Array'; } export function isBlob(value) { return getObjectType(value) === 'Blob'; } export function isBoolean(value) { return value === true || value === false; } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export function isBoundFunction(value) { return isFunction(value) && !Object.hasOwn(value, 'prototype'); } /** Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) */ export function isBuffer(value) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access return value?.constructor?.isBuffer?.(value) ?? false; } export function isClass(value) { return isFunction(value) && /^class(?:\s+|\{)/v.test(value.toString()); } export function isDataView(value) { return getObjectType(value) === 'DataView'; } export function isDate(value) { return getObjectType(value) === 'Date'; } export function isDirectInstanceOf(instance, class_) { if (instance === undefined || instance === null) { return false; } return Object.getPrototypeOf(instance) === class_.prototype; } export function isEmptyArray(value) { return isArray(value) && value.length === 0; } export function isEmptyMap(value) { return isMap(value) && value.size === 0; } export function isEmptyObject(value) { return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0; } export function isEmptySet(value) { return isSet(value) && value.size === 0; } export function isEmptyString(value) { return isString(value) && value.length === 0; } export function isEmptyStringOrWhitespace(value) { return isEmptyString(value) || isWhitespaceString(value); } export function isEnumCase(value, targetEnum) { // Numeric enums have reverse mappings (e.g. `Direction[0] = "Up"`), so their runtime object contains both `{ Up: 0 }` and `{ "0": "Up" }`. Filtering out entries that round-trip like a canonical number and point back to an own property leaves only actual enum member values. const enumObject = targetEnum; return Object.entries(enumObject).some(([key, enumValue]) => { if (!isString(enumValue)) { return enumValue === value; } const numericKey = Number(key); if (Number.isNaN(numericKey) || String(numericKey) !== key) { return enumValue === value; } return enumValue === value && !(Object.hasOwn(enumObject, enumValue) && enumObject[enumValue] === numericKey); }); } export function isError(value) { // TODO: Use `Error.isError` when targeting Node.js 24. return getObjectType(value) === 'Error'; } export function isEvenInteger(value) { return isAbsoluteModule2(0)(value); } // Example: `is.falsy = (value: unknown): value is (not true | 0 | '' | undefined | null) => Boolean(value);` export function isFalsy(value) { return !value; } export function isFiniteNumber(value) { return Number.isFinite(value); } // TODO: Support detecting Float16Array when targeting Node.js 24. export function isFloat32Array(value) { return getObjectType(value) === 'Float32Array'; } export function isFloat64Array(value) { return getObjectType(value) === 'Float64Array'; } export function isFormData(value) { return getObjectType(value) === 'FormData'; } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export function isFunction(value) { return typeof value === 'function'; } export function isGenerator(value) { return isIterable(value) && isFunction(value?.next) && isFunction(value?.throw); } export function isGeneratorFunction(value) { return getObjectType(value) === 'GeneratorFunction'; } const NODE_TYPE_ELEMENT = 1; // eslint-disable-line @typescript-eslint/naming-convention const DOM_PROPERTIES_TO_CHECK = [ 'innerHTML', 'ownerDocument', 'style', 'attributes', 'nodeValue', ]; export function isHtmlElement(value) { return isObject(value) && value.nodeType === NODE_TYPE_ELEMENT && isString(value.nodeName) && !isPlainObject(value) && DOM_PROPERTIES_TO_CHECK.every(property => property in value); } export function isInfinite(value) { return value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY; } export function isInRange(value, range) { if (isNumber(range)) { return value >= Math.min(0, range) && value <= Math.max(range, 0); } if (isArray(range) && range.length === 2) { if (Number.isNaN(range[0]) || Number.isNaN(range[1])) { throw new TypeError(`Invalid range: ${JSON.stringify(range)}`); } return value >= Math.min(...range) && value <= Math.max(...range); } throw new TypeError(`Invalid range: ${JSON.stringify(range)}`); } export function isInt16Array(value) { return getObjectType(value) === 'Int16Array'; } export function isInt32Array(value) { return getObjectType(value) === 'Int32Array'; } export function isInt8Array(value) { return getObjectType(value) === 'Int8Array'; } export function isInteger(value) { return Number.isInteger(value); } export function isIterable(value) { return isFunction(value?.[Symbol.iterator]); } export function isMap(value) { return getObjectType(value) === 'Map'; } export function isNan(value) { return Number.isNaN(value); } export function isNativePromise(value) { return getObjectType(value) === 'Promise'; } export function isNegativeInteger(value) { return isInteger(value) && value < 0; } export function isNegativeNumber(value) { return isNumber(value) && value < 0; } export function isNodeStream(value) { return isObject(value) && isFunction(value.pipe) && !isObservable(value); } export function isNonEmptyArray(value) { return isArray(value) && value.length > 0; } export function isNonEmptyMap(value) { return isMap(value) && value.size > 0; } // TODO: Use `not` operator here to remove `Map` and `Set` from type guard: // - https://github.com/Microsoft/TypeScript/pull/29317 export function isNonEmptyObject(value) { return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0; } export function isNonEmptySet(value) { return isSet(value) && value.size > 0; } // TODO: Use `not ''` when the `not` operator is available. export function isNonEmptyString(value) { return isString(value) && value.length > 0; } // TODO: Use `not ''` when the `not` operator is available. export function isNonEmptyStringAndNotWhitespace(value) { return isString(value) && !isEmptyStringOrWhitespace(value); } export function isNonNegativeInteger(value) { return isInteger(value) && value >= 0; } export function isNonNegativeNumber(value) { return isNumber(value) && value >= 0; } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function isNull(value) { return value === null; } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function isNullOrUndefined(value) { return isNull(value) || isUndefined(value); } export function isNumber(value) { return typeof value === 'number' && !Number.isNaN(value); } export function isNumericString(value) { return isString(value) && !isEmptyStringOrWhitespace(value) && value === value.trim() && !Number.isNaN(Number(value)); } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function isObject(value) { return !isNull(value) && (typeof value === 'object' || isFunction(value)); } export function isObservable(value) { if (!value) { return false; } // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access if (Symbol.observable !== undefined && value === value[Symbol.observable]?.()) { return true; } // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access if (value === value['@@observable']?.()) { return true; } return false; } export function isOddInteger(value) { return isAbsoluteModule2(1)(value); } export function isOneOf(values) { return (value) => values.includes(value); } export function isPlainObject(value) { // From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js if (typeof value !== 'object' || value === null) { return false; } // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const prototype = Object.getPrototypeOf(value); return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value); } export function isPositiveInteger(value) { return isInteger(value) && value > 0; } export function isPositiveNumber(value) { return isNumber(value) && value > 0; } export function isPrimitive(value) { return isNull(value) || isPrimitiveTypeName(typeof value); } export function isPromise(value) { return isNativePromise(value) || hasPromiseApi(value); } // `PropertyKey` is any value that can be used as an object key (string, number, or symbol). Note: NaN is technically `typeof 'number'` and thus fits TypeScript's `PropertyKey`, but we intentionally exclude it here because using NaN as a property key is almost always a mistake. export function isPropertyKey(value) { return isAny([isString, isNumber, isSymbol], value); } export function isRegExp(value) { return getObjectType(value) === 'RegExp'; } export function isSafeInteger(value) { return Number.isSafeInteger(value); } export function isSet(value) { return getObjectType(value) === 'Set'; } export function isSharedArrayBuffer(value) { return getObjectType(value) === 'SharedArrayBuffer'; } export function isString(value) { return typeof value === 'string'; } export function isSymbol(value) { return typeof value === 'symbol'; } // Example: `is.truthy = (value: unknown): value is (not false | not 0 | not '' | not undefined | not null) => Boolean(value);` // eslint-disable-next-line unicorn/prefer-native-coercion-functions export function isTruthy(value) { return Boolean(value); } export function isTupleLike(value, guards) { if (isArray(guards) && isArray(value) && guards.length === value.length) { return guards.every((guard, index) => guard(value[index])); } return false; } export function isTypedArray(value) { return isTypedArrayName(getObjectType(value)); } export function isUint16Array(value) { return getObjectType(value) === 'Uint16Array'; } export function isUint32Array(value) { return getObjectType(value) === 'Uint32Array'; } export function isUint8Array(value) { return getObjectType(value) === 'Uint8Array'; } export function isUint8ClampedArray(value) { return getObjectType(value) === 'Uint8ClampedArray'; } export function isUndefined(value) { return value === undefined; } export function isUrlInstance(value) { return getObjectType(value) === 'URL'; } // eslint-disable-next-line unicorn/prevent-abbreviations export function isUrlSearchParams(value) { return getObjectType(value) === 'URLSearchParams'; } export function isUrlString(value) { if (!isString(value)) { return false; } try { new URL(value); // eslint-disable-line no-new return true; } catch { return false; } } export function isValidDate(value) { return isDate(value) && !isNan(Number(value)); } export function isValidLength(value) { return isSafeInteger(value) && value >= 0; } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function isWeakMap(value) { return getObjectType(value) === 'WeakMap'; } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function isWeakRef(value) { return getObjectType(value) === 'WeakRef'; } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function isWeakSet(value) { return getObjectType(value) === 'WeakSet'; } export function isWhitespaceString(value) { return isString(value) && /^\s+$/v.test(value); } function predicateOnArray(method, predicate, values) { validatePredicate(predicate); if (values.length === 0) { throw new TypeError('Invalid number of values'); } return method.call(values, predicate); } function typeErrorMessage(description, value) { return `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`; } function typeErrorMessageNot(description, value) { return `Expected value which is not \`${description}\`, received value of type \`${is(value)}\`.`; } function unique(values) { // eslint-disable-next-line unicorn/prefer-spread return Array.from(new Set(values)); } const andFormatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }); const orFormatter = new Intl.ListFormat('en', { style: 'long', type: 'disjunction' }); function typeErrorMessageMultipleValues(expectedType, values) { const uniqueExpectedTypes = unique((isArray(expectedType) ? expectedType : [expectedType]).map(value => `\`${value}\``)); const uniqueValueTypes = unique(values.map(value => `\`${is(value)}\``)); return `Expected values which are ${orFormatter.format(uniqueExpectedTypes)}. Received values of type${uniqueValueTypes.length > 1 ? 's' : ''} ${andFormatter.format(uniqueValueTypes)}.`; } // Negative assertions are limited to types where the assertion rejects every TypeScript value assignable to the forbidden type. Structural object types such as `Map`, `Set`, `Date`, and `Array` are excluded because TypeScript accepts shape-compatible mocks while the runtime checks use object brands, so `Exclude` would narrow values that can pass the negative assertion. function createAssertNot(predicate, description) { return (value, message) => { if (predicate(value)) { throw new TypeError(message ?? typeErrorMessageNot(description, value)); } }; } export const assertNotUndefined = createAssertNot(isUndefined, 'undefined'); // eslint-disable-next-line @typescript-eslint/no-restricted-types export const assertNotNull = createAssertNot(isNull, 'null'); // eslint-disable-next-line @typescript-eslint/no-restricted-types export const assertNotNullOrUndefined // eslint-disable-next-line @typescript-eslint/no-restricted-types = createAssertNot(isNullOrUndefined, 'null or undefined'); export const assertNotString = createAssertNot(isString, 'string'); export const assertNotBoolean = createAssertNot(isBoolean, 'boolean'); export const assertNotSymbol = createAssertNot(isSymbol, 'symbol'); export const assertNotBigint = createAssertNot(isBigint, 'bigint'); export const assertNotPrimitive = createAssertNot(isPrimitive, 'primitive'); // eslint-disable-line @typescript-eslint/no-restricted-types // We intentionally do not support `assert.not(is.undefined, value)`. TypeScript cannot derive safe complement types from arbitrary predicates, and many predicates here are refinements (for example, `is.number` rejects `NaN`). Explicit methods keep runtime checks and type narrowing aligned. const notAssertions = { bigint: assertNotBigint, boolean: assertNotBoolean, null: assertNotNull, nullOrUndefined: assertNotNullOrUndefined, primitive: assertNotPrimitive, string: assertNotString, symbol: assertNotSymbol, undefined: assertNotUndefined, }; export const assert = { all: assertAll, any: assertAny, not: notAssertions, optional: assertOptional, array: assertArray, arrayBuffer: assertArrayBuffer, arrayLike: assertArrayLike, asyncFunction: assertAsyncFunction, asyncGenerator: assertAsyncGenerator, asyncGeneratorFunction: assertAsyncGeneratorFunction, asyncIterable: assertAsyncIterable, bigint: assertBigint, bigInt64Array: assertBigInt64Array, bigUint64Array: assertBigUint64Array, blob: assertBlob, boolean: assertBoolean, boundFunction: assertBoundFunction, buffer: assertBuffer, class: assertClass, dataView: assertDataView, date: assertDate, directInstanceOf: assertDirectInstanceOf, emptyArray: assertEmptyArray, emptyMap: assertEmptyMap, emptyObject: assertEmptyObject, emptySet: assertEmptySet, emptyString: assertEmptyString, emptyStringOrWhitespace: assertEmptyStringOrWhitespace, enumCase: assertEnumCase, error: assertError, evenInteger: assertEvenInteger, falsy: assertFalsy, finiteNumber: assertFiniteNumber, float32Array: assertFloat32Array, float64Array: assertFloat64Array, formData: assertFormData, function: assertFunction, generator: assertGenerator, generatorFunction: assertGeneratorFunction, htmlElement: assertHtmlElement, infinite: assertInfinite, inRange: assertInRange, int16Array: assertInt16Array, int32Array: assertInt32Array, int8Array: assertInt8Array, integer: assertInteger, iterable: assertIterable, map: assertMap, nan: assertNan, nativePromise: assertNativePromise, negativeInteger: assertNegativeInteger, negativeNumber: assertNegativeNumber, nodeStream: assertNodeStream, nonEmptyArray: assertNonEmptyArray, nonEmptyMap: assertNonEmptyMap, nonEmptyObject: assertNonEmptyObject, nonEmptySet: assertNonEmptySet, nonEmptyString: assertNonEmptyString, nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace, nonNegativeInteger: assertNonNegativeInteger, nonNegativeNumber: assertNonNegativeNumber, null: assertNull, nullOrUndefined: assertNullOrUndefined, number: assertNumber, numericString: assertNumericString, object: assertObject, observable: assertObservable, oddInteger: assertOddInteger, plainObject: assertPlainObject, positiveInteger: assertPositiveInteger, positiveNumber: assertPositiveNumber, primitive: assertPrimitive, promise: assertPromise, propertyKey: assertPropertyKey, regExp: assertRegExp, safeInteger: assertSafeInteger, set: assertSet, sharedArrayBuffer: assertSharedArrayBuffer, string: assertString, symbol: assertSymbol, truthy: assertTruthy, tupleLike: assertTupleLike, typedArray: assertTypedArray, uint16Array: assertUint16Array, uint32Array: assertUint32Array, uint8Array: assertUint8Array, uint8ClampedArray: assertUint8ClampedArray, undefined: assertUndefined, urlInstance: assertUrlInstance, urlSearchParams: assertUrlSearchParams, urlString: assertUrlString, validDate: assertValidDate, validLength: assertValidLength, weakMap: assertWeakMap, weakRef: assertWeakRef, weakSet: assertWeakSet, whitespaceString: assertWhitespaceString, }; const methodTypeMap = { isArray: 'Array', isArrayBuffer: 'ArrayBuffer', isArrayLike: 'array-like', isAsyncFunction: 'AsyncFunction', isAsyncGenerator: 'AsyncGenerator', isAsyncGeneratorFunction: 'AsyncGeneratorFunction', isAsyncIterable: 'AsyncIterable', isBigint: 'bigint', isBigInt64Array: 'BigInt64Array', isBigUint64Array: 'BigUint64Array', isBlob: 'Blob', isBoolean: 'boolean', isBoundFunction: 'bound Function', isBuffer: 'Buffer', isClass: 'Class', isDataView: 'DataView', isDate: 'Date', isDirectInstanceOf: 'T', isEmptyArray: 'empty array', isEmptyMap: 'empty map', isEmptyObject: 'empty object', isEmptySet: 'empty set', isEmptyString: 'empty string', isEmptyStringOrWhitespace: 'empty string or whitespace', isEnumCase: 'EnumCase', isError: 'Error', isEvenInteger: 'even integer', isFalsy: 'falsy', isFiniteNumber: 'finite number', isFloat32Array: 'Float32Array', isFloat64Array: 'Float64Array', isFormData: 'FormData', isFunction: 'Function', isGenerator: 'Generator', isGeneratorFunction: 'GeneratorFunction', isHtmlElement: 'HTMLElement', isInfinite: 'infinite number', isInRange: 'in range', isInt16Array: 'Int16Array', isInt32Array: 'Int32Array', isInt8Array: 'Int8Array', isInteger: 'integer', isIterable: 'Iterable', isMap: 'Map', isNan: 'NaN', isNativePromise: 'native Promise', isNegativeInteger: 'negative integer', isNegativeNumber: 'negative number', isNodeStream: 'Node.js Stream', isNonEmptyArray: 'non-empty array', isNonEmptyMap: 'non-empty map', isNonEmptyObject: 'non-empty object', isNonEmptySet: 'non-empty set', isNonEmptyString: 'non-empty string', isNonEmptyStringAndNotWhitespace: 'non-empty string and not whitespace', isNonNegativeInteger: 'non-negative integer', isNonNegativeNumber: 'non-negative number', isNull: 'null', isNullOrUndefined: 'null or undefined', isNumber: 'number', isNumericString: 'string with a number', isObject: 'Object', isObservable: 'Observable', isOddInteger: 'odd integer', isPlainObject: 'plain object', isPositiveInteger: 'positive integer', isPositiveNumber: 'positive number', isPrimitive: 'primitive', isPromise: 'Promise', isPropertyKey: 'PropertyKey', isRegExp: 'RegExp', isSafeInteger: 'safe integer', isSet: 'Set', isSharedArrayBuffer: 'SharedArrayBuffer', isString: 'string', isSymbol: 'symbol', isTruthy: 'truthy', isTupleLike: 'tuple-like', isTypedArray: 'TypedArray', isUint16Array: 'Uint16Array', isUint32Array: 'Uint32Array', isUint8Array: 'Uint8Array', isUint8ClampedArray: 'Uint8ClampedArray', isUndefined: 'undefined', isUrlInstance: 'URL', isUrlSearchParams: 'URLSearchParams', isUrlString: 'string with a URL', isValidDate: 'valid Date', isValidLength: 'valid length', isWeakMap: 'WeakMap', isWeakRef: 'WeakRef', isWeakSet: 'WeakSet', isWhitespaceString: 'whitespace string', }; const isMethodNames = keysOf(methodTypeMap); function isIsMethodName(value) { return isMethodNames.includes(value); } export function assertAll(predicate, ...values) { if (values.length === 0) { throw new TypeError('Invalid number of values'); } if (!isAll(predicate, ...values)) { const predicateFunction = predicate; const expectedType = !Array.isArray(predicate) && isIsMethodName(predicateFunction.name) ? methodTypeMap[predicateFunction.name] : 'predicate returns truthy for all values'; throw new TypeError(typeErrorMessageMultipleValues(expectedType, values)); } } export function assertAny(predicate, ...values) { if (values.length === 0) { throw new TypeError('Invalid number of values'); } if (!isAny(predicate, ...values)) { const predicates = Array.isArray(predicate) ? predicate : [predicate]; const expectedTypes = predicates.map(singlePredicate => isIsMethodName(singlePredicate.name) ? methodTypeMap[singlePredicate.name] : 'predicate returns truthy for any value'); throw new TypeError(typeErrorMessageMultipleValues(expectedTypes, values)); } } export function assertOptional(value, assertion, message) { if (!isUndefined(value)) { assertion(value, message); } } export function assertArray(value, assertion, message) { if (!isArray(value)) { throw new TypeError(message ?? typeErrorMessage('Array', value)); } if (assertion) { for (const element of value) { // @ts-expect-error: "Assertions require every name in the call target to be declared with an explicit type annotation." assertion(element, message); } } } export function assertArrayBuffer(value, message) { if (!isArrayBuffer(value)) { throw new TypeError(message ?? typeErrorMessage('ArrayBuffer', value)); } } export function assertArrayLike(value, message) { if (!isArrayLike(value)) { throw new TypeError(message ?? typeErrorMessage('array-like', value)); } } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export function assertAsyncFunction(value, message) { if (!isAsyncFunction(value)) { throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value)); } } export function assertAsyncGenerator(value, message) { if (!isAsyncGenerator(value)) { throw new TypeError(message ?? typeErrorMessage('AsyncGenerator', value)); } } export function assertAsyncGeneratorFunction(value, message) { if (!isAsyncGeneratorFunction(value)) { throw new TypeError(message ?? typeErrorMessage('AsyncGeneratorFunction', value)); } } export function assertAsyncIterable(value, message) { if (!isAsyncIterable(value)) { throw new TypeError(message ?? typeErrorMessage('AsyncIterable', value)); } } export function assertBigint(value, message) { if (!isBigint(value)) { throw new TypeError(message ?? typeErrorMessage('bigint', value)); } } export function assertBigInt64Array(value, message) { if (!isBigInt64Array(value)) { throw new TypeError(message ?? typeErrorMessage('BigInt64Array', value)); } } export function assertBigUint64Array(value, message) { if (!isBigUint64Array(value)) { throw new TypeError(message ?? typeErrorMessage('BigUint64Array', value)); } } export function assertBlob(value, message) { if (!isBlob(value)) { throw new TypeError(message ?? typeErrorMessage('Blob', value)); } } export function assertBoolean(value, message) { if (!isBoolean(value)) { throw new TypeError(message ?? typeErrorMessage('boolean', value)); } } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export function assertBoundFunction(value, message) { if (!isBoundFunction(value)) { throw new TypeError(message ?? typeErrorMessage('bound Function', value)); } } /** Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) */ export function assertBuffer(value, message) { if (!isBuffer(value)) { throw new TypeError(message ?? typeErrorMessage('Buffer', value)); } } export function assertClass(value, message) { if (!isClass(value)) { throw new TypeError(message ?? typeErrorMessage('Class', value)); } } export function assertDataView(value, message) { if (!isDataView(value)) { throw new TypeError(message ?? typeErrorMessage('DataView', value)); } } export function assertDate(value, message) { if (!isDate(value)) { throw new TypeError(message ?? typeErrorMessage('Date', value)); } } export function assertDirectInstanceOf(instance, class_, message) { if (!isDirectInstanceOf(instance, class_)) { throw new TypeError(message ?? typeErrorMessage('T', instance)); } } export function assertEmptyArray(value, message) { if (!isEmptyArray(value)) { throw new TypeError(message ?? typeErrorMessage('empty array', value)); } } export function assertEmptyMap(value, message) { if (!isEmptyMap(value)) { throw new TypeError(message ?? typeErrorMessage('empty map', value)); } } export function assertEmptyObject(value, message) { if (!isEmptyObject(value)) { throw new TypeError(message ?? typeErrorMessage('empty object', value)); } } export function assertEmptySet(value, message) { if (!isEmptySet(value)) { throw new TypeError(message ?? typeErrorMessage('empty set', value)); } } export function assertEmptyString(value, message) { if (!isEmptyString(value)) { throw new TypeError(message ?? typeErrorMessage('empty string', value)); } } export function assertEmptyStringOrWhitespace(value, message) { if (!isEmptyStringOrWhitespace(value)) { throw new TypeError(message ?? typeErrorMessage('empty string or whitespace', value)); } } export function assertEnumCase(value, targetEnum, message) { if (!isEnumCase(value, targetEnum)) { throw new TypeError(message ?? typeErrorMessage('EnumCase', value)); } } export function assertError(value, message) { if (!isError(value)) { throw new TypeError(message ?? typeErrorMessage('Error', value)); } } export function assertEvenInteger(value, message) { if (!isEvenInteger(value)) { throw new TypeError(message ?? typeErrorMessage('even integer', value)); } } export function assertFalsy(value, message) { if (!isFalsy(value)) { throw new TypeError(message ?? typeErrorMessage('falsy', value)); } } export function assertFiniteNumber(value, message) { if (!isFiniteNumber(value)) { throw new TypeError(message ?? typeErrorMessage('finite number', value)); } } export function assertFloat32Array(value, message) { if (!isFloat32Array(value)) { throw new TypeError(message ?? typeErrorMessage('Float32Array', value)); } } export function assertFloat64Array(value, message) { if (!isFloat64Array(value)) { throw new TypeError(message ?? typeErrorMessage('Float64Array', value)); } } export function assertFormData(value, message) { if (!isFormData(value)) { throw new TypeError(message ?? typeErrorMessage('FormData', value)); } } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export function assertFunction(value, message) { if (!isFunction(value)) { throw new TypeError(message ?? typeErrorMessage('Function', value)); } } export function assertGenerator(value, message) { if (!isGenerator(value)) { throw new TypeError(message ?? typeErrorMessage('Generator', value)); } } export function assertGeneratorFunction(value, message) { if (!isGeneratorFunction(value)) { throw new TypeError(message ?? typeErrorMessage('GeneratorFunction', value)); } } export function assertHtmlElement(value, message) { if (!isHtmlElement(value)) { throw new TypeError(message ?? typeErrorMessage('HTMLElement', value)); } } export function assertInfinite(value, message) { if (!isInfinite(value)) { throw new TypeError(message ?? typeErrorMessage('infinite number', value)); } } export function assertInRange(value, range, message) { if (!isInRange(value, range)) { throw new TypeError(message ?? typeErrorMessage('in range', value)); } } export function assertInt16Array(value, message) { if (!isInt16Array(value)) { throw new TypeError(message ?? typeErrorMessage('Int16Array', value)); } } export function assertInt32Array(value, message) { if (!isInt32Array(value)) { throw new TypeError(message ?? typeErrorMessage('Int32Array', value)); } } export function assertInt8Array(value, message) { if (!isInt8Array(value)) { throw new TypeError(message ?? typeErrorMessage('Int8Array', value)); } } export function assertInteger(value, message) { if (!isInteger(value)) { throw new TypeError(message ?? typeErrorMessage('integer', value)); } } export function assertIterable(value, message) { if (!isIterable(value)) { throw new TypeError(message ?? typeErrorMessage('Iterable', value)); } } export function assertMap(value, message) { if (!isMap(value)) { throw new TypeError(message ?? typeErrorMessage('Map', value)); } } export function assertNan(value, message) { if (!isNan(value)) { throw new TypeError(message ?? typeErrorMessage('NaN', value)); } } export function assertNativePromise(value, message) { if (!isNativePromise(value)) { throw new TypeError(message ?? typeErrorMessage('native Promise', value)); } } export function assertNegativeInteger(value, message) { if (!isNegativeInteger(value)) { throw new TypeError(message ?? typeErrorMessage('negative integer', value)); } } export function assertNegativeNumber(value, message) { if (!isNegativeNumber(value)) { throw new TypeError(message ?? typeErrorMessage('negative number', value)); } } export function assertNodeStream(value, message) { if (!isNodeStream(value)) { throw new TypeError(message ?? typeErrorMessage('Node.js Stream', value)); } } export function assertNonEmptyArray(value, message) { if (!isNonEmptyArray(value)) { throw new TypeError(message ?? typeErrorMessage('non-empty array', value)); } } export function assertNonEmptyMap(value, message) { if (!isNonEmptyMap(value)) { throw new TypeError(message ?? typeErrorMessage('non-empty map', value)); } } export function assertNonEmptyObject(value, message) { if (!isNonEmptyObject(value)) { throw new TypeError(message ?? typeErrorMessage('non-empty object', value)); } } export function assertNonEmptySet(value, message) { if (!isNonEmptySet(value)) { throw new TypeError(message ?? typeErrorMessage('non-empty set', value)); } } export function assertNonEmptyString(value, message) { if (!isNonEmptyString(value)) { throw new TypeError(message ?? typeErrorMessage('non-empty string', value)); } } export function assertNonEmptyStringAndNotWhitespace(value, message) { if (!isNonEmptyStringAndNotWhitespace(value)) { throw new TypeError(message ?? typeErrorMessage('non-empty string and not whitespace', value)); } } export function assertNonNegativeInteger(value, message) { if (!isNonNegativeInteger(value)) { throw new TypeError(message ?? typeErrorMessage('non-negative integer', value)); } } export function assertNonNegativeNumber(value, message) { if (!isNonNegativeNumber(value)) { throw new TypeError(message ?? typeErrorMessage('non-negative number', value)); } } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function assertNull(value, message) { if (!isNull(value)) { throw new TypeError(message ?? typeErrorMessage('null', value)); } } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function assertNullOrUndefined(value, message) { if (!isNullOrUndefined(value)) { throw new TypeError(message ?? typeErrorMessage('null or undefined', value)); } } export function assertNumber(value, message) { if (!isNumber(value)) { throw new TypeError(message ?? typeErrorMessage('number', value)); } } export function assertNumericString(value, message) { if (!isNumericString(value)) { throw new TypeError(message ?? typeErrorMessage('string with a number', value)); } } // eslint-disable-next-line @typescript-eslint/no-restricted-types export function assertObject(value, message) { if (!isObject(value)) { throw new TypeError(message ?? typeErrorMessage('Object', value)); } } export function assertObservable(value, message) { if (!isObservable(value)) { throw new TypeError(message ?? typeErrorMessage('Observable', value)); } } export function assertOddInteger(value, message) { if (!isOddInteger(value)) { throw new TypeError(message ?? typeErrorMessage('odd integer', value)); } } export function assertPlainObject(value, message) { if (!isPlainObject(value)) { throw new TypeError(message ?? typeErrorMessage('plain object', value)); } } export function assertPositiveInteger(value, message) { if (!isPositiveInteger(value)) { throw new TypeError(message ?? typeErrorMessage('positive integer', value)); } } export function assertPositiveNumber(value, message) { if (!isPositiveNumber(value)) { throw new TypeError(message ?? typeErrorMessage('positive number', value)); } } export function assertPrimitive(value, message) { if (!isPrimitive(value)) { throw new TypeError(message ?? typeErrorMessage('primitive', value)); } } export function assertPromise(value, message) { if (!isPromise(value)) { throw new TypeError(message ?? typeErrorMessage('Promise', value)); } } export function assertPropertyKey(value, message) { if (!isPropertyKey(value)) { throw new TypeError(message ?? typeErrorMessage('PropertyKey', value)); } } export function assertRegExp(value, message) { if (!isRegExp(value)) { throw new TypeError(message ?? typeErrorMessage('RegExp', value)); } } export function assertSafeInteger(value, message) { if (!isSafeInteger(value)) { throw new TypeError(message ?? typeErrorMessage('safe integer', value)); } } export function assertSet(value, message) { if (!isSet(value)) { throw new TypeError(message ?? typeErrorMessage('Set', value)); } } export function assertSharedArrayBuffer(value, message) { if (!isSharedArrayBuffer(value)) { throw new TypeError(message ?? typeErrorMessage('SharedArrayBuffer', value)); } } export function assertString(value, message) { if (!isString(value)) { throw new TypeError(message ?? typeErrorMessage('string', value)); } } export function assertSymbol(value, message) { if (!isSymbol(value)) { throw new TypeError(message ?? typeErrorMessage('symbol', value)); } } export function assertTruthy(value, message) { if (!isTruthy(value)) { throw new TypeError(message ?? typeErrorMessage('truthy', value)); } } export function assertTupleLike(value, guards, message) { if (!isTupleLike(value, guards)) { throw new TypeError(message ?? typeErrorMessage('tuple-like', value)); } } export function assertTypedArray(value, message) { if (!isTypedArray(value)) { throw new TypeError(message ?? typeErrorMessage('TypedArray', value)); } } export function assertUint16Array(value, message) { if (!isUint16Array(value)) { throw new TypeError(message ?? typeErrorMessage('Uint16Array', value)); } } export function assertUint32Array(value, message) { if (!isUint32Array(value)) { throw new TypeError(message ?? typeErrorMessage('Uint32Array', value)); } } export function assertUint8Array(value, message) { if (!isUint8Array(value)) { throw new TypeError(message ?? typeErrorMessage('Uint8Array', value)); } } export function assertUint8ClampedArray(value, message) { if (!isUint8ClampedArray(value)) { throw new TypeError(message ?? typeErrorMessage('Uint8ClampedArray', value)); } } export function assertUndefined(value, message) { if (!isUndefined(value)) { throw new TypeError(message ?? typeErrorMessage('undefined', value)); } } export function assertUrlInstance(value, message) { if (!isUrlInstance(value)) { throw new TypeError(message ?? typeErrorMessage('URL', value)); } } // eslint-disable-next-line unicorn/prevent-abbreviations export function assertUrlSearchParams(value, message) { if (!isUrlSearchParams(value)) { throw n