diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33db234..734c8eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,11 +10,10 @@ jobs: fail-fast: false matrix: node-version: - - 24 - - 22 + - 20 steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 2996cf5..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,9 +0,0 @@ -# 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` = `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`). - -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`. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 120000 index 47dc3e3..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -AGENTS.md \ No newline at end of file diff --git a/package.json b/package.json index d7a386f..9e2de0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sindresorhus/is", - "version": "8.1.0", + "version": "7.1.1", "description": "Type check values", "license": "MIT", "repository": "sindresorhus/is", @@ -17,11 +17,11 @@ }, "sideEffects": false, "engines": { - "node": ">=22" + "node": ">=18" }, "scripts": { "build": "del distribution && tsc", - "test": "tsc --noEmit && tsc --project test/tsconfig.json --noEmit && xo && node --experimental-transform-types --test test/test.ts", + "test": "tsc --noEmit && xo && ava", "prepare": "npm run build" }, "files": [ @@ -51,26 +51,31 @@ "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", + "@sindresorhus/tsconfig": "^6.0.0", + "@types/jsdom": "^21.1.7", + "@types/node": "^20.14.10", "@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", + "ava": "^6.1.3", + "del-cli": "^5.1.0", + "expect-type": "^0.19.0", + "jsdom": "^24.1.0", + "rxjs": "^7.8.1", + "tempy": "^3.1.0", + "tsimp": "2.0.11", + "typescript": "5.5.3", + "xo": "^0.58.0", "zen-observable": "^0.10.0" + }, + "ava": { + "environmentVariables": { + "TSIMP_DIAG": "error" + }, + "extensions": { + "ts": "module" + }, + "nodeArguments": [ + "--import=tsimp/import" + ] } } diff --git a/readme.md b/readme.md index 509f75f..9a4982c 100644 --- a/readme.md +++ b/readme.md @@ -130,17 +130,6 @@ 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) @@ -474,10 +463,6 @@ function foo() { 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. @@ -486,22 +471,6 @@ Check if `value` is a number and is more than 0. 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. @@ -606,31 +575,6 @@ 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`: @@ -643,28 +587,6 @@ 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`. @@ -680,17 +602,6 @@ 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. @@ -786,44 +697,6 @@ handleMovieRatingApiResponse({rating: 0.87, title: 'The Matrix'}); 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`. diff --git a/source/index.ts b/source/index.ts index 6c2f428..f5c8fdd 100644 --- a/source/index.ts +++ b/source/index.ts @@ -1,33 +1,18 @@ import type { ArrayLike, Class, - EvenInteger, Falsy, - FiniteNumber, - Integer, - NaN as NaNType, - NegativeInfinity, - NegativeInteger, - NegativeNumber, NodeStream, NonEmptyString, - NonNegativeInteger, - NonNegativeNumber, ObservableLike, - OddInteger, Predicate, Primitive, - PositiveInfinity, - PositiveInteger, - PositiveNumber, - SafeInteger, TypedArray, UrlString, - ValidLength, WeakRef, Whitespace, -} from './types.ts'; -import {keysOf} from './utilities.ts'; +} from './types.js'; +import {keysOf} from './utilities.js'; // From type-fest. type ExtractFromGlobalConstructors = @@ -37,15 +22,6 @@ type ExtractFromGlobalConstructors = type NodeBuffer = ExtractFromGlobalConstructors<'Buffer'>; -type NumericGuardResult = - ( - unknown extends Input - ? Branded - : Input extends number - ? Branded & Input - : number - ) & Input; - const typedArrayTypeNames = [ 'Int8Array', 'Uint8Array', @@ -123,7 +99,6 @@ function isPrimitiveTypeName(name: unknown): name is PrimitiveTypeName { export type TypeName = ObjectTypeName | PrimitiveTypeName; const assertionTypeDescriptions = [ - 'bound Function', 'positive number', 'negative number', 'Class', @@ -158,13 +133,7 @@ const assertionTypeDescriptions = [ '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', @@ -181,7 +150,7 @@ export type AssertionTypeDescription = typeof assertionTypeDescriptions[number]; const getObjectType = (value: unknown): ObjectTypeName | undefined => { const objectTypeName = Object.prototype.toString.call(value).slice(8, -1); - if (/HTML\w+Element/v.test(objectTypeName) && isHtmlElement(value)) { + if (/HTML\w+Element/.test(objectTypeName) && isHtmlElement(value)) { return 'HTMLElement'; } @@ -197,7 +166,6 @@ function detect(value: unknown): TypeName { return 'null'; } - // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (typeof value) { case 'undefined': { return 'undefined'; @@ -243,7 +211,7 @@ function detect(value: unknown): TypeName { } const tagType = getObjectType(value); - if (tagType !== undefined && tagType !== 'Object') { + if (tagType && tagType !== 'Object') { return tagType; } @@ -251,7 +219,7 @@ function detect(value: unknown): TypeName { return 'Promise'; } - if (isBoxedPrimitiveObject(value)) { + if (value instanceof String || value instanceof Boolean || value instanceof Number) { throw new TypeError('Please don\'t use object wrappers for primitive types'); } @@ -262,23 +230,6 @@ function hasPromiseApi(value: unknown): value is Promise { return isFunction((value as Promise)?.then) && isFunction((value as Promise)?.catch); } -function hasBoxedPrimitiveBrand(value: unknown, valueOf: () => unknown): boolean { - 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: unknown): boolean { - return hasBoxedPrimitiveBrand(value, String.prototype.valueOf) - || hasBoxedPrimitiveBrand(value, Boolean.prototype.valueOf) - || hasBoxedPrimitiveBrand(value, Number.prototype.valueOf); -} - const is = Object.assign( detect, { @@ -287,7 +238,6 @@ const is = Object.assign( array: isArray, arrayBuffer: isArrayBuffer, arrayLike: isArrayLike, - arrayOf: isArrayOf, asyncFunction: isAsyncFunction, asyncGenerator: isAsyncGenerator, asyncGeneratorFunction: isAsyncGeneratorFunction, @@ -314,7 +264,6 @@ const is = Object.assign( error: isError, evenInteger: isEvenInteger, falsy: isFalsy, - finiteNumber: isFiniteNumber, float32Array: isFloat32Array, float64Array: isFloat64Array, formData: isFormData, @@ -332,7 +281,6 @@ const is = Object.assign( map: isMap, nan: isNan, nativePromise: isNativePromise, - negativeInteger: isNegativeInteger, negativeNumber: isNegativeNumber, nodeStream: isNodeStream, nonEmptyArray: isNonEmptyArray, @@ -341,8 +289,6 @@ const is = Object.assign( nonEmptySet: isNonEmptySet, nonEmptyString: isNonEmptyString, nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace, - nonNegativeInteger: isNonNegativeInteger, - nonNegativeNumber: isNonNegativeNumber, null: isNull, nullOrUndefined: isNullOrUndefined, number: isNumber, @@ -350,9 +296,7 @@ const is = Object.assign( object: isObject, observable: isObservable, oddInteger: isOddInteger, - oneOf: isOneOf, plainObject: isPlainObject, - positiveInteger: isPositiveInteger, positiveNumber: isPositiveNumber, primitive: isPrimitive, promise: isPromise, @@ -388,81 +332,15 @@ function isAbsoluteModule2(remainder: 0 | 1) { return (value: unknown): value is number => isInteger(value) && Math.abs(value % 2) === remainder; } -type TypeGuard = (value: unknown) => value is T; - -function validatePredicateArray(predicateArray: readonly Predicate[], allowEmpty: boolean) { - 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); - } +export function isAll(predicate: Predicate, ...values: unknown[]): boolean { + return predicateOnArray(Array.prototype.every, predicate, values); } -function validatePredicate(predicate: Predicate) { - if (!isFunction(predicate)) { - throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); - } -} - -// Predicate factory overloads - return a type guard when called with only predicates -export function isAll(predicates: [TypeGuard]): TypeGuard; -export function isAll(predicates: [TypeGuard, TypeGuard]): TypeGuard; -export function isAll(predicates: [TypeGuard, TypeGuard, TypeGuard]): TypeGuard; -export function isAll(predicates: [TypeGuard, TypeGuard, TypeGuard, TypeGuard]): TypeGuard; -export function isAll(predicates: [TypeGuard, TypeGuard, TypeGuard, TypeGuard, TypeGuard]): TypeGuard; -export function isAll(predicates: ReadonlyArray>): TypeGuard; -export function isAll(predicates: readonly Predicate[]): Predicate; -// Evaluator overload - check if all values match the predicate -export function isAll(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean; -export function isAll(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean | Predicate { - if (Array.isArray(predicate)) { - const predicateArray = predicate as readonly Predicate[]; - validatePredicateArray(predicateArray, values.length === 0); - - const combinedPredicate = (value: unknown) => predicateArray.every(singlePredicate => singlePredicate(value)); - if (values.length === 0) { - return combinedPredicate; - } - - return predicateOnArray(Array.prototype.every, combinedPredicate, values); - } - - return predicateOnArray(Array.prototype.every, predicate as Predicate, values); -} - -// Predicate factory overloads - return a type guard when called with only predicates -export function isAny(predicates: [TypeGuard]): TypeGuard; -export function isAny(predicates: [TypeGuard, TypeGuard]): TypeGuard; -export function isAny(predicates: [TypeGuard, TypeGuard, TypeGuard]): TypeGuard; -export function isAny(predicates: [TypeGuard, TypeGuard, TypeGuard, TypeGuard]): TypeGuard; -export function isAny(predicates: [TypeGuard, TypeGuard, TypeGuard, TypeGuard, TypeGuard]): TypeGuard; -export function isAny(predicates: ReadonlyArray>): TypeGuard; -export function isAny(predicates: readonly Predicate[]): Predicate; -// Evaluator overload - check if any value matches any predicate -export function isAny(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean; -export function isAny(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean | Predicate { - if (Array.isArray(predicate)) { - const predicateArray = predicate as readonly Predicate[]; - validatePredicateArray(predicateArray, values.length === 0); - - const combinedPredicate = (value: unknown) => predicateArray.some(singlePredicate => singlePredicate(value)); - if (values.length === 0) { - return combinedPredicate; - } - - return predicateOnArray(Array.prototype.some, combinedPredicate, values); - } - - return predicateOnArray(Array.prototype.some, predicate as Predicate, values); +export function isAny(predicate: Predicate | Predicate[], ...values: unknown[]): boolean { + const predicates = isArray(predicate) ? predicate : [predicate]; + return predicates.some(singlePredicate => + predicateOnArray(Array.prototype.some, singlePredicate, values), + ); } export function isOptional(value: unknown, predicate: (value: unknown) => value is T): value is T | undefined { @@ -490,10 +368,6 @@ export function isArrayLike(value: unknown): value is ArrayLike return !isNullOrUndefined(value) && !isFunction(value) && isValidLength((value as ArrayLike).length); } -export function isArrayOf(predicate: (value: unknown) => value is T): (value: unknown) => value is T[] { - return (value: unknown): value is T[] => isArray(value) && value.every(element => predicate(element)); -} - export function isAsyncFunction(value: unknown): value is ((...arguments_: any[]) => Promise) { return getObjectType(value) === 'AsyncFunction'; } @@ -530,7 +404,7 @@ export function isBoolean(value: unknown): value is boolean { return value === true || value === false; } -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +// eslint-disable-next-line @typescript-eslint/ban-types export function isBoundFunction(value: unknown): value is Function { return isFunction(value) && !Object.hasOwn(value, 'prototype'); } @@ -539,12 +413,12 @@ export function isBoundFunction(value: unknown): value is Function { Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer) */ export function isBuffer(value: unknown): value is NodeBuffer { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call return (value as any)?.constructor?.isBuffer?.(value) ?? false; } export function isClass(value: unknown): value is Class { - return isFunction(value) && /^class(?:\s+|\{)/v.test(value.toString()); + return isFunction(value) && /^class(\s+|{)/.test(value.toString()); } export function isDataView(value: unknown): value is DataView { @@ -572,7 +446,7 @@ export function isEmptyMap(value: unknown): value is Map { } export function isEmptyObject(value: unknown): value is Record { - return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0; + return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0; } export function isEmptySet(value: unknown): value is Set { @@ -588,31 +462,16 @@ export function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitesp } export function isEnumCase(value: unknown, targetEnum: T): value is T[keyof T] { - // 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 as Record; - - 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); - }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return Object.values(targetEnum as any).includes(value as string); } export function isError(value: unknown): value is Error { - // TODO: Use `Error.isError` when targeting Node.js 24. + // TODO: Use `Error.isError` when targeting Node.js 24.` return getObjectType(value) === 'Error'; } -// For numeric guards, preserve branded narrowing for `unknown`, keep the false branch usable for plain `number`, and still narrow mixed unions to `number`. -export function isEvenInteger(value: Input): value is NumericGuardResult; -export function isEvenInteger(value: unknown): boolean { +export function isEvenInteger(value: unknown): value is number { return isAbsoluteModule2(0)(value); } @@ -621,11 +480,6 @@ export function isFalsy(value: unknown): value is Falsy { return !value; } -export function isFiniteNumber(value: Input): value is NumericGuardResult; -export function isFiniteNumber(value: unknown): boolean { - return Number.isFinite(value); -} - // TODO: Support detecting Float16Array when targeting Node.js 24. export function isFloat32Array(value: unknown): value is Float32Array { @@ -640,7 +494,7 @@ export function isFormData(value: unknown): value is FormData { return getObjectType(value) === 'FormData'; } -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +// eslint-disable-next-line @typescript-eslint/ban-types export function isFunction(value: unknown): value is Function { return typeof value === 'function'; } @@ -653,9 +507,11 @@ export function isGeneratorFunction(value: unknown): value is GeneratorFunction return getObjectType(value) === 'GeneratorFunction'; } -const NODE_TYPE_ELEMENT = 1; // eslint-disable-line @typescript-eslint/naming-convention +// eslint-disable-next-line @typescript-eslint/naming-convention +const NODE_TYPE_ELEMENT = 1; -const DOM_PROPERTIES_TO_CHECK: Array<(keyof HTMLElement)> = [ // eslint-disable-line @typescript-eslint/naming-convention +// eslint-disable-next-line @typescript-eslint/naming-convention +const DOM_PROPERTIES_TO_CHECK: Array<(keyof HTMLElement)> = [ 'innerHTML', 'ownerDocument', 'style', @@ -671,8 +527,7 @@ export function isHtmlElement(value: unknown): value is HTMLElement { && DOM_PROPERTIES_TO_CHECK.every(property => property in value); } -export function isInfinite(value: Input): value is NumericGuardResult; -export function isInfinite(value: unknown): boolean { +export function isInfinite(value: unknown): value is number { return value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY; } @@ -682,10 +537,6 @@ export function isInRange(value: number, range: number | [number, number]): valu } 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); } @@ -704,8 +555,7 @@ export function isInt8Array(value: unknown): value is Int8Array { return getObjectType(value) === 'Int8Array'; } -export function isInteger(value: Input): value is NumericGuardResult; -export function isInteger(value: unknown): boolean { +export function isInteger(value: unknown): value is number { return Number.isInteger(value); } @@ -717,8 +567,7 @@ export function isMap(value: unknown): value is return getObjectType(value) === 'Map'; } -export function isNan(value: Input): value is NumericGuardResult; -export function isNan(value: unknown): boolean { +export function isNan(value: unknown) { return Number.isNaN(value); } @@ -726,13 +575,7 @@ export function isNativePromise(value: unknown): value is Promise(value: Input): value is NumericGuardResult; -export function isNegativeInteger(value: unknown): boolean { - return isInteger(value) && value < 0; -} - -export function isNegativeNumber(value: Input): value is NumericGuardResult; -export function isNegativeNumber(value: unknown): boolean { +export function isNegativeNumber(value: unknown): value is number { return isNumber(value) && value < 0; } @@ -751,7 +594,7 @@ export function isNonEmptyMap(value: unknown): v // TODO: Use `not` operator here to remove `Map` and `Set` from type guard: // - https://github.com/Microsoft/TypeScript/pull/29317 export function isNonEmptyObject(value: unknown): value is Record { - return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0; + return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0; } export function isNonEmptySet(value: unknown): value is Set { @@ -768,22 +611,12 @@ export function isNonEmptyStringAndNotWhitespace(value: unknown): value is NonEm return isString(value) && !isEmptyStringOrWhitespace(value); } -export function isNonNegativeInteger(value: Input): value is NumericGuardResult; -export function isNonNegativeInteger(value: unknown): boolean { - return isInteger(value) && value >= 0; -} - -export function isNonNegativeNumber(value: Input): value is NumericGuardResult; -export function isNonNegativeNumber(value: unknown): boolean { - return isNumber(value) && value >= 0; -} - -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function isNull(value: unknown): value is null { return value === null; } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function isNullOrUndefined(value: unknown): value is null | undefined { return isNull(value) || isUndefined(value); } @@ -793,10 +626,10 @@ export function isNumber(value: unknown): value is number { } export function isNumericString(value: unknown): value is `${number}` { - return isString(value) && !isEmptyStringOrWhitespace(value) && value === value.trim() && !Number.isNaN(Number(value)); + return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value)); } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function isObject(value: unknown): value is object { return !isNull(value) && (typeof value === 'object' || isFunction(value)); } @@ -806,12 +639,12 @@ export function isObservable(value: unknown): value is ObservableLike { return false; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line no-use-extend-native/no-use-extend-native, @typescript-eslint/no-unsafe-call if (Symbol.observable !== undefined && value === (value as any)[Symbol.observable]?.()) { return true; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line @typescript-eslint/no-unsafe-call if (value === (value as any)['@@observable']?.()) { return true; } @@ -819,15 +652,10 @@ export function isObservable(value: unknown): value is ObservableLike { return false; } -export function isOddInteger(value: Input): value is NumericGuardResult; -export function isOddInteger(value: unknown): boolean { +export function isOddInteger(value: unknown): value is number { return isAbsoluteModule2(1)(value); } -export function isOneOf(values: T): (value: unknown) => value is T[number] { - return (value: unknown): value is T[number] => values.includes(value); -} - export function isPlainObject(value: unknown): value is Record { // From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js if (typeof value !== 'object' || value === null) { @@ -840,13 +668,7 @@ export function isPlainObject(value: unknown): value is Record< return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value); } -export function isPositiveInteger(value: Input): value is NumericGuardResult; -export function isPositiveInteger(value: unknown): boolean { - return isInteger(value) && value > 0; -} - -export function isPositiveNumber(value: Input): value is NumericGuardResult; -export function isPositiveNumber(value: unknown): boolean { +export function isPositiveNumber(value: unknown): value is number { return isNumber(value) && value > 0; } @@ -858,7 +680,7 @@ export function isPromise(value: unknown): value is Promise { 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. +// `PropertyKey` is any value that can be used as an object key (string, number, or symbol) export function isPropertyKey(value: unknown): value is PropertyKey { return isAny([isString, isNumber, isSymbol], value); } @@ -867,8 +689,7 @@ export function isRegExp(value: unknown): value is RegExp { return getObjectType(value) === 'RegExp'; } -export function isSafeInteger(value: Input): value is NumericGuardResult; -export function isSafeInteger(value: unknown): boolean { +export function isSafeInteger(value: unknown): value is number { return Number.isSafeInteger(value); } @@ -894,8 +715,10 @@ export function isTruthy(value: T | Falsy): value is T { return Boolean(value); } -// eslint-disable-next-line @typescript-eslint/no-restricted-types -type ResolveTypesOfTypeGuardsTuple = +type TypeGuard = (value: unknown) => value is T; + +// eslint-disable-next-line @typescript-eslint/ban-types +type ResolveTypesOfTypeGuardsTuple = TypeGuardsOfT extends [TypeGuard, ...infer TOthers] ? ResolveTypesOfTypeGuardsTuple : TypeGuardsOfT extends undefined[] @@ -960,34 +783,35 @@ export function isValidDate(value: unknown): value is Date { return isDate(value) && !isNan(Number(value)); } -export function isValidLength(value: Input): value is NumericGuardResult; -export function isValidLength(value: unknown): boolean { +export function isValidLength(value: unknown): value is number { return isSafeInteger(value) && value >= 0; } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function isWeakMap(value: unknown): value is WeakMap { return getObjectType(value) === 'WeakMap'; } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations export function isWeakRef(value: unknown): value is WeakRef { return getObjectType(value) === 'WeakRef'; } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function isWeakSet(value: unknown): value is WeakSet { return getObjectType(value) === 'WeakSet'; } export function isWhitespaceString(value: unknown): value is Whitespace { - return isString(value) && /^\s+$/v.test(value); + return isString(value) && /^\s+$/.test(value); } type ArrayMethod = (function_: (value: unknown, index: number, array: unknown[]) => boolean, thisArgument?: unknown) => boolean; function predicateOnArray(method: ArrayMethod, predicate: Predicate, values: unknown[]) { - validatePredicate(predicate); + if (!isFunction(predicate)) { + throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); + } if (values.length === 0) { throw new TypeError('Invalid number of values'); @@ -1000,17 +824,6 @@ function typeErrorMessage(description: AssertionTypeDescription, value: unknown) return `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`; } -function typeErrorMessageNot(description: AssertionTypeDescription, value: unknown): string { - return `Expected value which is not \`${description}\`, received value of type \`${is(value)}\`.`; -} - -type NotAssertionResult = Exclude & ([unknown] extends [Value] ? UnknownResult : unknown); - -type NotAssertion = (value: Value, message?: string) => asserts value is NotAssertionResult; - -// eslint-disable-next-line @typescript-eslint/no-restricted-types -type UnknownNotPrimitive = Exclude | object; - function unique(values: T[]): T[] { // eslint-disable-next-line unicorn/prefer-spread return Array.from(new Set(values)); @@ -1026,24 +839,17 @@ function typeErrorMessageMultipleValues(expectedType: AssertionTypeDescription | } // Type assertions have to be declared with an explicit type. -// Keep assertion outputs unbranded even when the corresponding `is.*` guard uses a branded subtype. -// The brands exist to preserve useful false-branch narrowing for type guards on `number` inputs, which does not apply to `asserts`. type Assert = { // Unknowns. undefined: (value: unknown, message?: string) => asserts value is undefined; string: (value: unknown, message?: string) => asserts value is string; number: (value: unknown, message?: string) => asserts value is number; - finiteNumber: (value: unknown, message?: string) => asserts value is number; positiveNumber: (value: unknown, message?: string) => asserts value is number; - negativeInteger: (value: unknown, message?: string) => asserts value is number; negativeNumber: (value: unknown, message?: string) => asserts value is number; - nonNegativeInteger: (value: unknown, message?: string) => asserts value is number; - nonNegativeNumber: (value: unknown, message?: string) => asserts value is number; - positiveInteger: (value: unknown, message?: string) => asserts value is number; bigint: (value: unknown, message?: string) => asserts value is bigint; - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + // eslint-disable-next-line @typescript-eslint/ban-types function: (value: unknown, message?: string) => asserts value is Function; - // eslint-disable-next-line @typescript-eslint/no-restricted-types + // eslint-disable-next-line @typescript-eslint/ban-types null: (value: unknown, message?: string) => asserts value is null; class: (value: unknown, message?: string) => asserts value is Class; boolean: (value: unknown, message?: string) => asserts value is boolean; @@ -1052,7 +858,7 @@ type Assert = { array: (value: unknown, assertion?: (element: unknown) => asserts element is T, message?: string) => asserts value is T[]; buffer: (value: unknown, message?: string) => asserts value is NodeBuffer; blob: (value: unknown, message?: string) => asserts value is Blob; - // eslint-disable-next-line @typescript-eslint/no-restricted-types + // eslint-disable-next-line @typescript-eslint/ban-types nullOrUndefined: (value: unknown, message?: string) => asserts value is null | undefined; object: (value: unknown, message?: string) => asserts value is Record; iterable: (value: unknown, message?: string) => asserts value is Iterable; @@ -1063,20 +869,20 @@ type Assert = { promise: (value: unknown, message?: string) => asserts value is Promise; generatorFunction: (value: unknown, message?: string) => asserts value is GeneratorFunction; asyncGeneratorFunction: (value: unknown, message?: string) => asserts value is AsyncGeneratorFunction; - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + // eslint-disable-next-line @typescript-eslint/ban-types asyncFunction: (value: unknown, message?: string) => asserts value is Function; - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + // eslint-disable-next-line @typescript-eslint/ban-types boundFunction: (value: unknown, message?: string) => asserts value is Function; regExp: (value: unknown, message?: string) => asserts value is RegExp; date: (value: unknown, message?: string) => asserts value is Date; error: (value: unknown, message?: string) => asserts value is Error; map: (value: unknown, message?: string) => asserts value is Map; set: (value: unknown, message?: string) => asserts value is Set; - // eslint-disable-next-line @typescript-eslint/no-restricted-types + // eslint-disable-next-line @typescript-eslint/ban-types weakMap: (value: unknown, message?: string) => asserts value is WeakMap; - // eslint-disable-next-line @typescript-eslint/no-restricted-types + // eslint-disable-next-line @typescript-eslint/ban-types weakSet: (value: unknown, message?: string) => asserts value is WeakSet; - // eslint-disable-next-line @typescript-eslint/no-restricted-types + // eslint-disable-next-line @typescript-eslint/ban-types weakRef: (value: unknown, message?: string) => asserts value is WeakRef; int8Array: (value: unknown, message?: string) => asserts value is Int8Array; uint8Array: (value: unknown, message?: string) => asserts value is Uint8Array; @@ -1136,11 +942,9 @@ type Assert = { directInstanceOf: (instance: unknown, class_: Class, message?: string) => asserts instance is T; inRange: (value: number, range: number | [number, number], message?: string) => asserts value is number; - not: NotAssert; - // Variadic functions. - any: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never; - all: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never; + any: (predicate: Predicate | Predicate[], ...values: unknown[]) => void | never; + all: (predicate: Predicate, ...values: unknown[]) => void | never; /** Asserts that `value` is `undefined` or satisfies the provided `assertion`. @@ -1150,58 +954,9 @@ type Assert = { optional: (value: unknown, assertion: (value: unknown, message?: string) => asserts value is T, message?: string) => asserts value is T | undefined; }; -type NotAssert = { - undefined: NotAssertion>; - // eslint-disable-next-line @typescript-eslint/no-restricted-types - null: NotAssertion>; - // eslint-disable-next-line @typescript-eslint/no-restricted-types - nullOrUndefined: NotAssertion>; - string: NotAssertion>; - boolean: NotAssertion>; - symbol: NotAssertion>; - bigint: NotAssertion>; - // eslint-disable-next-line @typescript-eslint/no-restricted-types - primitive: NotAssertion; -}; - -// 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: Predicate, description: AssertionTypeDescription): NotAssertion { - return (value: Value, message?: string): asserts value is NotAssertionResult => { - if (predicate(value)) { - throw new TypeError(message ?? typeErrorMessageNot(description, value)); - } - }; -} - -export const assertNotUndefined: NotAssertion> = createAssertNot>(isUndefined, 'undefined'); -// eslint-disable-next-line @typescript-eslint/no-restricted-types -export const assertNotNull: NotAssertion> = createAssertNot>(isNull, 'null'); -// eslint-disable-next-line @typescript-eslint/no-restricted-types -export const assertNotNullOrUndefined: NotAssertion> - // eslint-disable-next-line @typescript-eslint/no-restricted-types - = createAssertNot>(isNullOrUndefined, 'null or undefined'); -export const assertNotString: NotAssertion> = createAssertNot>(isString, 'string'); -export const assertNotBoolean: NotAssertion> = createAssertNot>(isBoolean, 'boolean'); -export const assertNotSymbol: NotAssertion> = createAssertNot>(isSymbol, 'symbol'); -export const assertNotBigint: NotAssertion> = createAssertNot>(isBigint, 'bigint'); -export const assertNotPrimitive: NotAssertion = 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: NotAssert = { - bigint: assertNotBigint, - boolean: assertNotBoolean, - null: assertNotNull, - nullOrUndefined: assertNotNullOrUndefined, - primitive: assertNotPrimitive, - string: assertNotString, - symbol: assertNotSymbol, - undefined: assertNotUndefined, -}; - export const assert: Assert = { all: assertAll, any: assertAny, - not: notAssertions, optional: assertOptional, array: assertArray, arrayBuffer: assertArrayBuffer, @@ -1231,7 +986,6 @@ export const assert: Assert = { error: assertError, evenInteger: assertEvenInteger, falsy: assertFalsy, - finiteNumber: assertFiniteNumber, float32Array: assertFloat32Array, float64Array: assertFloat64Array, formData: assertFormData, @@ -1249,7 +1003,6 @@ export const assert: Assert = { map: assertMap, nan: assertNan, nativePromise: assertNativePromise, - negativeInteger: assertNegativeInteger, negativeNumber: assertNegativeNumber, nodeStream: assertNodeStream, nonEmptyArray: assertNonEmptyArray, @@ -1258,8 +1011,6 @@ export const assert: Assert = { nonEmptySet: assertNonEmptySet, nonEmptyString: assertNonEmptyString, nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace, - nonNegativeInteger: assertNonNegativeInteger, - nonNegativeNumber: assertNonNegativeNumber, null: assertNull, nullOrUndefined: assertNullOrUndefined, number: assertNumber, @@ -1268,7 +1019,6 @@ export const assert: Assert = { observable: assertObservable, oddInteger: assertOddInteger, plainObject: assertPlainObject, - positiveInteger: assertPositiveInteger, positiveNumber: assertPositiveNumber, primitive: assertPrimitive, promise: assertPromise, @@ -1311,7 +1061,7 @@ const methodTypeMap = { isBigUint64Array: 'BigUint64Array', isBlob: 'Blob', isBoolean: 'boolean', - isBoundFunction: 'bound Function', + isBoundFunction: 'Function', isBuffer: 'Buffer', isClass: 'Class', isDataView: 'DataView', @@ -1327,7 +1077,6 @@ const methodTypeMap = { isError: 'Error', isEvenInteger: 'even integer', isFalsy: 'falsy', - isFiniteNumber: 'finite number', isFloat32Array: 'Float32Array', isFloat64Array: 'Float64Array', isFormData: 'FormData', @@ -1345,7 +1094,6 @@ const methodTypeMap = { isMap: 'Map', isNan: 'NaN', isNativePromise: 'native Promise', - isNegativeInteger: 'negative integer', isNegativeNumber: 'negative number', isNodeStream: 'Node.js Stream', isNonEmptyArray: 'non-empty array', @@ -1354,8 +1102,6 @@ const methodTypeMap = { 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', @@ -1364,13 +1110,12 @@ const methodTypeMap = { 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', + isSafeInteger: 'integer', isSet: 'Set', isSharedArrayBuffer: 'SharedArrayBuffer', isString: 'string', @@ -1401,26 +1146,17 @@ function isIsMethodName(value: unknown): value is IsMethodName { return isMethodNames.includes(value as IsMethodName); } -export function assertAll(predicate: Predicate | readonly Predicate[], ...values: unknown[]): void | never { - if (values.length === 0) { - throw new TypeError('Invalid number of values'); - } - +export function assertAll(predicate: Predicate, ...values: unknown[]): void | never { if (!isAll(predicate, ...values)) { - const predicateFunction = predicate as Predicate; - const expectedType = !Array.isArray(predicate) && isIsMethodName(predicateFunction.name) ? methodTypeMap[predicateFunction.name] : 'predicate returns truthy for all values'; + const expectedType = isIsMethodName(predicate.name) ? methodTypeMap[predicate.name] : 'predicate returns truthy for all values'; throw new TypeError(typeErrorMessageMultipleValues(expectedType, values)); } } -export function assertAny(predicate: Predicate | readonly Predicate[], ...values: unknown[]): void | never { - if (values.length === 0) { - throw new TypeError('Invalid number of values'); - } - +export function assertAny(predicate: Predicate | Predicate[], ...values: unknown[]): void | never { if (!isAny(predicate, ...values)) { - const predicates = Array.isArray(predicate) ? predicate as readonly Predicate[] : [predicate as Predicate]; - const expectedTypes = predicates.map(singlePredicate => isIsMethodName(singlePredicate.name) ? methodTypeMap[singlePredicate.name] : 'predicate returns truthy for any value'); + const predicates = isArray(predicate) ? predicate : [predicate]; + const expectedTypes = predicates.map(predicate => isIsMethodName(predicate.name) ? methodTypeMap[predicate.name] : 'predicate returns truthy for any value'); throw new TypeError(typeErrorMessageMultipleValues(expectedTypes, values)); } } @@ -1456,7 +1192,7 @@ export function assertArrayLike(value: unknown, message?: string): } } -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +// eslint-disable-next-line @typescript-eslint/ban-types export function assertAsyncFunction(value: unknown, message?: string): asserts value is Function { if (!isAsyncFunction(value)) { throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value)); @@ -1511,10 +1247,10 @@ export function assertBoolean(value: unknown, message?: string): asserts value i } } -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +// eslint-disable-next-line @typescript-eslint/ban-types export function assertBoundFunction(value: unknown, message?: string): asserts value is Function { if (!isBoundFunction(value)) { - throw new TypeError(message ?? typeErrorMessage('bound Function', value)); + throw new TypeError(message ?? typeErrorMessage('Function', value)); } } @@ -1611,12 +1347,6 @@ export function assertFalsy(value: unknown, message?: string): asserts value is } } -export function assertFiniteNumber(value: unknown, message?: string): asserts value is number { - if (!isFiniteNumber(value)) { - throw new TypeError(message ?? typeErrorMessage('finite number', value)); - } -} - export function assertFloat32Array(value: unknown, message?: string): asserts value is Float32Array { if (!isFloat32Array(value)) { throw new TypeError(message ?? typeErrorMessage('Float32Array', value)); @@ -1635,7 +1365,7 @@ export function assertFormData(value: unknown, message?: string): asserts value } } -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +// eslint-disable-next-line @typescript-eslint/ban-types export function assertFunction(value: unknown, message?: string): asserts value is Function { if (!isFunction(value)) { throw new TypeError(message ?? typeErrorMessage('Function', value)); @@ -1720,12 +1450,6 @@ export function assertNativePromise(value: unknown, message?: strin } } -export function assertNegativeInteger(value: unknown, message?: string): asserts value is number { - if (!isNegativeInteger(value)) { - throw new TypeError(message ?? typeErrorMessage('negative integer', value)); - } -} - export function assertNegativeNumber(value: unknown, message?: string): asserts value is number { if (!isNegativeNumber(value)) { throw new TypeError(message ?? typeErrorMessage('negative number', value)); @@ -1774,26 +1498,14 @@ export function assertNonEmptyStringAndNotWhitespace(value: unknown, message?: s } } -export function assertNonNegativeInteger(value: unknown, message?: string): asserts value is number { - if (!isNonNegativeInteger(value)) { - throw new TypeError(message ?? typeErrorMessage('non-negative integer', value)); - } -} - -export function assertNonNegativeNumber(value: unknown, message?: string): asserts value is number { - if (!isNonNegativeNumber(value)) { - throw new TypeError(message ?? typeErrorMessage('non-negative number', value)); - } -} - -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function assertNull(value: unknown, message?: string): asserts value is null { if (!isNull(value)) { throw new TypeError(message ?? typeErrorMessage('null', value)); } } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function assertNullOrUndefined(value: unknown, message?: string): asserts value is null | undefined { if (!isNullOrUndefined(value)) { throw new TypeError(message ?? typeErrorMessage('null or undefined', value)); @@ -1812,7 +1524,7 @@ export function assertNumericString(value: unknown, message?: string): asserts v } } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function assertObject(value: unknown, message?: string): asserts value is object { if (!isObject(value)) { throw new TypeError(message ?? typeErrorMessage('Object', value)); @@ -1837,12 +1549,6 @@ export function assertPlainObject(value: unknown, message?: str } } -export function assertPositiveInteger(value: unknown, message?: string): asserts value is number { - if (!isPositiveInteger(value)) { - throw new TypeError(message ?? typeErrorMessage('positive integer', value)); - } -} - export function assertPositiveNumber(value: unknown, message?: string): asserts value is number { if (!isPositiveNumber(value)) { throw new TypeError(message ?? typeErrorMessage('positive number', value)); @@ -1861,7 +1567,7 @@ export function assertPromise(value: unknown, message?: string): as } } -export function assertPropertyKey(value: unknown, message?: string): asserts value is PropertyKey { +export function assertPropertyKey(value: unknown, message?: string): asserts value is number { if (!isPropertyKey(value)) { throw new TypeError(message ?? typeErrorMessage('PropertyKey', value)); } @@ -1875,7 +1581,7 @@ export function assertRegExp(value: unknown, message?: string): asserts value is export function assertSafeInteger(value: unknown, message?: string): asserts value is number { if (!isSafeInteger(value)) { - throw new TypeError(message ?? typeErrorMessage('safe integer', value)); + throw new TypeError(message ?? typeErrorMessage('integer', value)); } } @@ -1982,21 +1688,21 @@ export function assertValidLength(value: unknown, message?: string): asserts val } } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function assertWeakMap(value: unknown, message?: string): asserts value is WeakMap { if (!isWeakMap(value)) { throw new TypeError(message ?? typeErrorMessage('WeakMap', value)); } } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations export function assertWeakRef(value: unknown, message?: string): asserts value is WeakRef { if (!isWeakRef(value)) { throw new TypeError(message ?? typeErrorMessage('WeakRef', value)); } } -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export function assertWeakSet(value: unknown, message?: string): asserts value is WeakSet { if (!isWeakSet(value)) { throw new TypeError(message ?? typeErrorMessage('WeakSet', value)); @@ -2014,25 +1720,10 @@ export default is; export type { ArrayLike, Class, - EvenInteger, - FiniteNumber, - Integer, - NaN, - NegativeInfinity, - NegativeInteger, - NegativeNumber, NodeStream, - NonNegativeInteger, - NonNegativeNumber, ObservableLike, - OddInteger, - PositiveInfinity, - PositiveInteger, - PositiveNumber, Predicate, Primitive, - SafeInteger, TypedArray, UrlString, - ValidLength, -} from './types.ts'; +} from './types.js'; diff --git a/source/types.ts b/source/types.ts index 9255072..9ad9f2e 100644 --- a/source/types.ts +++ b/source/types.ts @@ -4,8 +4,7 @@ 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 + | null // eslint-disable-line @typescript-eslint/ban-types | undefined | string | number @@ -54,11 +53,10 @@ export type ObservableLike = { [Symbol.observable](): ObservableLike; }; -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/ban-types export type Falsy = false | 0 | 0n | '' | null | undefined; -// eslint-disable-next-line @typescript-eslint/no-restricted-types -export type WeakRef = { +export type WeakRef = { // eslint-disable-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations readonly [Symbol.toStringTag]: 'WeakRef'; deref(): T | undefined; }; @@ -78,122 +76,9 @@ export type NonEmptyString = string & {0: string}; export type Whitespace = ' '; -type Brand = Readonly>; - /** 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'>; diff --git a/source/utilities.ts b/source/utilities.ts index 686edb1..102b6db 100644 --- a/source/utilities.ts +++ b/source/utilities.ts @@ -1,3 +1,3 @@ export function keysOf>(value: T): Array { - return Object.keys(value) as Array; // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion + return Object.keys(value) as Array; } diff --git a/test/test.ts b/test/test.ts index 2f98bfb..4da5723 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,28 +1,25 @@ -/* eslint-disable @typescript-eslint/no-empty-function, @stylistic/curly-newline, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-empty-function */ import {Buffer} from 'node:buffer'; import fs from 'node:fs'; import net from 'node:net'; import Stream from 'node:stream'; import {inspect} from 'node:util'; -import {test} from 'node:test'; -import assert from 'node:assert/strict'; +import test, {type ExecutionContext} from 'ava'; import {JSDOM} from 'jsdom'; import {Subject, Observable} from 'rxjs'; import {temporaryFile} from 'tempy'; import {expectTypeOf} from 'expect-type'; import ZenObservable from 'zen-observable'; import is, { - assert as isAssert, - assertPropertyKey, + assert, type AssertionTypeDescription, - type NaN as NaNType, type Predicate, type Primitive, type TypedArray, type TypeName, type UrlString, -} from '../source/index.ts'; -import {keysOf} from '../source/utilities.ts'; +} from '../source/index.js'; +import {keysOf} from '../source/utilities.js'; class PromiseSubclassFixture extends Promise {} class ErrorSubclassFixture extends Error {} @@ -30,6 +27,8 @@ class ErrorSubclassFixture extends Error {} const {window} = new JSDOM(); const {document} = window; +const structuredClone = globalThis.structuredClone ?? (x => x); + type Test = Readonly<{ fixtures: unknown[]; typename?: TypeName; @@ -119,7 +118,7 @@ const primitiveTypes = { 1n, 0n, -0n, - 1234n, + BigInt('1234'), ], typename: 'bigint', }, @@ -157,7 +156,7 @@ const primitiveTypes = { safeInteger: { fixtures: [...reusableFixtures.integer, ...reusableFixtures.safeInteger], typename: 'number', - typeDescription: 'safe integer', + typeDescription: 'integer', }, infinite: { fixtures: [...reusableFixtures.infinite], @@ -209,16 +208,14 @@ const objectTypes = { object: { fixtures: [ Object.create({x: 1}), - {[Symbol.toStringTag]: 'String'}, ...reusableFixtures.plainObject, ], typename: 'Object', }, regExp: { fixtures: [ - /\w/v, - // eslint-disable-next-line prefer-regex-literals - new RegExp(String.raw`\w`, 'v'), + /\w/, + new RegExp('\\w'), // eslint-disable-line prefer-regex-literals ], typename: 'RegExp', }, @@ -282,7 +279,6 @@ const objectTypes = { boundFunction: { fixtures: [...reusableFixtures.boundFunction, ...reusableFixtures.asyncFunction], typename: 'Function', - typeDescription: 'bound Function', }, map: { fixtures: [ @@ -466,34 +462,23 @@ const subClasses = new Map([ ['object', keysOf(objectTypes)], ]); -const notAssertionFixtures = { - bigint: {fixture: 1n, nonFixture: '🦄', typeDescription: 'bigint'}, - boolean: {fixture: false, nonFixture: '🦄', typeDescription: 'boolean'}, - null: {fixture: null, nonFixture: '🦄', typeDescription: 'null'}, - nullOrUndefined: {fixtures: [null, undefined], nonFixture: '🦄', typeDescription: 'null or undefined'}, - primitive: {fixtures: [false, null, undefined], nonFixture: [], typeDescription: 'primitive'}, - string: {fixture: '🦄', nonFixture: 1, typeDescription: 'string'}, - symbol: {fixture: Symbol('🦄'), nonFixture: '🦄', typeDescription: 'symbol'}, - undefined: {fixture: undefined, nonFixture: null, typeDescription: 'undefined'}, -} as const satisfies Record; - // This ensures a certain method matches only the types it's supposed to and none of the other methods' types -for (const type of keysOf(types)) { - test(`is.${type}`, () => { +const exclusivelyTyped = test.macro({ + exec(t: ExecutionContext, type: TypeNameWithFixture) { const {fixtures, typeDescription, typename} = types[type] as Test; const valueType = typeDescription ?? typename ?? 'unspecified'; - const testAssert: (value: unknown) => never | void = isAssert[type]; + const testAssert: (value: unknown) => never | void = assert[type]; const testIs: Predicate = is[type]; for (const fixture of fixtures) { - assert.ok(testIs(fixture), `Value: ${inspect(fixture)}`); - assert.doesNotThrow(() => { + t.true(testIs(fixture), `Value: ${inspect(fixture)}`); + t.notThrows(() => { testAssert(fixture); }); - if (typename !== undefined) { - assert.strictEqual(is(fixture), typename); + if (typename) { + t.is(is(fixture), typename); } } @@ -509,541 +494,267 @@ for (const type of keysOf(types)) { continue; } - assert.strictEqual(testIs(fixture), false, `${key}.fixture[${i}]: ${inspect(fixture)} should not be ${type}`); - assert.throws(() => { + t.false(testIs(fixture), `${key}.fixture[${i}]: ${inspect(fixture)} should not be ${type}`); + t.throws(() => { testAssert(fixture); }, { message: `Expected value which is \`${valueType}\`, received value of type \`${is(fixture)}\`.`, }); } } - }); + }, + title(_, type: TypeNameWithFixture) { + return `is.${type}`; + }, +}); + +for (const type of keysOf(types)) { + test(exclusivelyTyped, type); } -test('is.positiveNumber', () => { - assert.ok(is.positiveNumber(6)); - assert.ok(is.positiveNumber(1.4)); - assert.ok(is.positiveNumber(Number.POSITIVE_INFINITY)); +test('is.positiveNumber', t => { + t.true(is.positiveNumber(6)); + t.true(is.positiveNumber(1.4)); + t.true(is.positiveNumber(Number.POSITIVE_INFINITY)); - assert.doesNotThrow(() => { - isAssert.positiveNumber(6); + t.notThrows(() => { + assert.positiveNumber(6); }); - assert.doesNotThrow(() => { - isAssert.positiveNumber(1.4); + t.notThrows(() => { + assert.positiveNumber(1.4); }); - assert.doesNotThrow(() => { - isAssert.positiveNumber(Number.POSITIVE_INFINITY); + t.notThrows(() => { + assert.positiveNumber(Number.POSITIVE_INFINITY); }); - assert.strictEqual(is.positiveNumber(0), false); - assert.strictEqual(is.positiveNumber(-0), false); - assert.strictEqual(is.positiveNumber(-6), false); - assert.strictEqual(is.positiveNumber(-1.4), false); - assert.strictEqual(is.positiveNumber(Number.NEGATIVE_INFINITY), false); - assert.strictEqual(is.positiveNumber(Number.NaN), false); + t.false(is.positiveNumber(0)); + t.false(is.positiveNumber(-0)); + t.false(is.positiveNumber(-6)); + t.false(is.positiveNumber(-1.4)); + t.false(is.positiveNumber(Number.NEGATIVE_INFINITY)); - assert.throws(() => { - isAssert.positiveNumber(0); + t.throws(() => { + assert.positiveNumber(0); }); - assert.throws(() => { - isAssert.positiveNumber(-0); + t.throws(() => { + assert.positiveNumber(-0); }); - assert.throws(() => { - isAssert.positiveNumber(-6); + t.throws(() => { + assert.positiveNumber(-6); }); - assert.throws(() => { - isAssert.positiveNumber(-1.4); + t.throws(() => { + assert.positiveNumber(-1.4); }); - assert.throws(() => { - isAssert.positiveNumber(Number.NEGATIVE_INFINITY); + t.throws(() => { + assert.positiveNumber(Number.NEGATIVE_INFINITY); }); }); -test('is.nan', () => { - assert.ok(is.nan(Number.NaN)); - assert.ok(is.nan(NaN)); // eslint-disable-line unicorn/prefer-number-properties +test('is.negativeNumber', t => { + t.true(is.negativeNumber(-6)); + t.true(is.negativeNumber(-1.4)); + t.true(is.negativeNumber(Number.NEGATIVE_INFINITY)); - assert.doesNotThrow(() => { - isAssert.nan(Number.NaN); + t.notThrows(() => { + assert.negativeNumber(-6); + }); + t.notThrows(() => { + assert.negativeNumber(-1.4); + }); + t.notThrows(() => { + assert.negativeNumber(Number.NEGATIVE_INFINITY); }); - assert.strictEqual(is.nan(0), false); - assert.strictEqual(is.nan(-0), false); - assert.strictEqual(is.nan(1), false); - assert.strictEqual(is.nan(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.nan(Number.NEGATIVE_INFINITY), false); - assert.strictEqual(is.nan('NaN'), false); - assert.strictEqual(is.nan(undefined), false); + t.false(is.negativeNumber(0)); + t.false(is.negativeNumber(-0)); + t.false(is.negativeNumber(6)); + t.false(is.negativeNumber(1.4)); + t.false(is.negativeNumber(Number.POSITIVE_INFINITY)); - assert.throws(() => { - isAssert.nan(0); + t.throws(() => { + assert.negativeNumber(0); }); - assert.throws(() => { - isAssert.nan(1); + t.throws(() => { + assert.negativeNumber(-0); }); - assert.throws(() => { - isAssert.nan('NaN'); + t.throws(() => { + assert.negativeNumber(6); + }); + t.throws(() => { + assert.negativeNumber(1.4); + }); + t.throws(() => { + assert.negativeNumber(Number.POSITIVE_INFINITY); }); }); -test('is.finiteNumber', () => { - assert.ok(is.finiteNumber(6)); - assert.ok(is.finiteNumber(-6)); - assert.ok(is.finiteNumber(0)); - assert.ok(is.finiteNumber(1.4)); - - assert.doesNotThrow(() => { - isAssert.finiteNumber(6); +test('is.numericString supplemental', t => { + t.false(is.numericString('')); + t.false(is.numericString(' ')); + t.false(is.numericString(' \t\t\n')); + t.false(is.numericString(1)); + t.throws(() => { + assert.numericString(''); }); - assert.doesNotThrow(() => { - isAssert.finiteNumber(0); - }); - - assert.strictEqual(is.finiteNumber(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.finiteNumber(Number.NEGATIVE_INFINITY), false); - assert.strictEqual(is.finiteNumber(Number.NaN), false); - - assert.throws(() => { - isAssert.finiteNumber(Number.POSITIVE_INFINITY); - }); - assert.throws(() => { - isAssert.finiteNumber(Number.NEGATIVE_INFINITY); - }); - assert.throws(() => { - isAssert.finiteNumber(Number.NaN); + t.throws(() => { + assert.numericString(1); }); }); -test('is.negativeNumber', () => { - assert.ok(is.negativeNumber(-6)); - assert.ok(is.negativeNumber(-1.4)); - assert.ok(is.negativeNumber(Number.NEGATIVE_INFINITY)); +test('is.array supplemental', t => { + t.true(is.array([1, 2, 3], is.number)); + t.false(is.array([1, '2', 3], is.number)); - assert.doesNotThrow(() => { - isAssert.negativeNumber(-6); - }); - assert.doesNotThrow(() => { - isAssert.negativeNumber(-1.4); - }); - assert.doesNotThrow(() => { - isAssert.negativeNumber(Number.NEGATIVE_INFINITY); + t.notThrows(() => { + assert.array([1, 2], assert.number); }); - assert.strictEqual(is.negativeNumber(0), false); - assert.strictEqual(is.negativeNumber(-0), false); - assert.strictEqual(is.negativeNumber(6), false); - assert.strictEqual(is.negativeNumber(1.4), false); - assert.strictEqual(is.negativeNumber(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.negativeNumber(Number.NaN), false); - - assert.throws(() => { - isAssert.negativeNumber(0); - }); - assert.throws(() => { - isAssert.negativeNumber(-0); - }); - assert.throws(() => { - isAssert.negativeNumber(6); - }); - assert.throws(() => { - isAssert.negativeNumber(1.4); - }); - assert.throws(() => { - isAssert.negativeNumber(Number.POSITIVE_INFINITY); - }); -}); - -test('is.nonNegativeNumber', () => { - assert.ok(is.nonNegativeNumber(0)); - assert.ok(is.nonNegativeNumber(6)); - assert.ok(is.nonNegativeNumber(1.4)); - assert.ok(is.nonNegativeNumber(Number.POSITIVE_INFINITY)); - - assert.doesNotThrow(() => { - isAssert.nonNegativeNumber(0); - }); - assert.doesNotThrow(() => { - isAssert.nonNegativeNumber(6); + t.throws(() => { + assert.array([1, '2'], assert.number); }); - assert.ok(is.nonNegativeNumber(-0)); // -0 >= 0 is true in JavaScript - assert.strictEqual(is.nonNegativeNumber(-6), false); - assert.strictEqual(is.nonNegativeNumber(-1.4), false); - assert.strictEqual(is.nonNegativeNumber(Number.NEGATIVE_INFINITY), false); - assert.strictEqual(is.nonNegativeNumber(Number.NaN), false); - - assert.throws(() => { - isAssert.nonNegativeNumber(-6); - }); - assert.throws(() => { - isAssert.nonNegativeNumber(Number.NEGATIVE_INFINITY); - }); -}); - -test('is.positiveInteger', () => { - assert.ok(is.positiveInteger(1)); - assert.ok(is.positiveInteger(6)); - assert.ok(is.positiveInteger(100)); - - assert.doesNotThrow(() => { - isAssert.positiveInteger(1); - }); - assert.doesNotThrow(() => { - isAssert.positiveInteger(6); - }); - - assert.strictEqual(is.positiveInteger(0), false); - assert.strictEqual(is.positiveInteger(-1), false); - assert.strictEqual(is.positiveInteger(1.5), false); - assert.strictEqual(is.positiveInteger(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.positiveInteger(Number.NaN), false); - - assert.throws(() => { - isAssert.positiveInteger(0); - }); - assert.throws(() => { - isAssert.positiveInteger(-1); - }); - assert.throws(() => { - isAssert.positiveInteger(1.5); - }); -}); - -test('is.negativeInteger', () => { - assert.ok(is.negativeInteger(-1)); - assert.ok(is.negativeInteger(-6)); - assert.ok(is.negativeInteger(-100)); - - assert.doesNotThrow(() => { - isAssert.negativeInteger(-1); - }); - assert.doesNotThrow(() => { - isAssert.negativeInteger(-6); - }); - - assert.strictEqual(is.negativeInteger(0), false); - assert.strictEqual(is.negativeInteger(-0), false); // -0 < 0 is false in JavaScript - assert.strictEqual(is.negativeInteger(1), false); - assert.strictEqual(is.negativeInteger(-1.5), false); - assert.strictEqual(is.negativeInteger(Number.NEGATIVE_INFINITY), false); - assert.strictEqual(is.negativeInteger(Number.NaN), false); - - assert.throws(() => { - isAssert.negativeInteger(0); - }); - assert.throws(() => { - isAssert.negativeInteger(1); - }); - assert.throws(() => { - isAssert.negativeInteger(-1.5); - }); - assert.throws(() => { - isAssert.negativeInteger(Number.NEGATIVE_INFINITY); - }); -}); - -test('is.nonNegativeInteger', () => { - assert.ok(is.nonNegativeInteger(0)); - assert.ok(is.nonNegativeInteger(1)); - assert.ok(is.nonNegativeInteger(100)); - - assert.doesNotThrow(() => { - isAssert.nonNegativeInteger(0); - }); - assert.doesNotThrow(() => { - isAssert.nonNegativeInteger(1); - }); - - assert.ok(is.nonNegativeInteger(-0)); // -0 >= 0 is true in JavaScript - - assert.strictEqual(is.nonNegativeInteger(-1), false); - assert.strictEqual(is.nonNegativeInteger(1.5), false); - assert.strictEqual(is.nonNegativeInteger(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.nonNegativeInteger(Number.NaN), false); - - assert.throws(() => { - isAssert.nonNegativeInteger(-1); - }); - assert.throws(() => { - isAssert.nonNegativeInteger(1.5); - }); - assert.throws(() => { - isAssert.nonNegativeInteger(Number.POSITIVE_INFINITY); - }); -}); - -test('is.infinite', () => { - assert.ok(is.infinite(Number.POSITIVE_INFINITY)); - assert.ok(is.infinite(Number.NEGATIVE_INFINITY)); - - assert.doesNotThrow(() => { - isAssert.infinite(Number.POSITIVE_INFINITY); - }); - assert.doesNotThrow(() => { - isAssert.infinite(Number.NEGATIVE_INFINITY); - }); - - assert.strictEqual(is.infinite(0), false); - assert.strictEqual(is.infinite(1), false); - assert.strictEqual(is.infinite(-1), false); - assert.strictEqual(is.infinite(Number.NaN), false); - assert.strictEqual(is.infinite(Number.MAX_VALUE), false); - assert.strictEqual(is.infinite('Infinity'), false); - - assert.throws(() => { - isAssert.infinite(0); - }); - assert.throws(() => { - isAssert.infinite(Number.NaN); - }); -}); - -test('is.numericString supplemental', () => { - assert.strictEqual(is.numericString(''), false); - assert.strictEqual(is.numericString(' '), false); - assert.strictEqual(is.numericString(' \t\t\n'), false); - assert.strictEqual(is.numericString(1), false); - assert.strictEqual(is.numericString(' 5'), false); - assert.strictEqual(is.numericString('5 '), false); - assert.strictEqual(is.numericString(' 5 '), false); - assert.strictEqual(is.numericString('\t3'), false); - assert.throws(() => { - isAssert.numericString(''); - }); - assert.throws(() => { - isAssert.numericString(1); - }); -}); - -test('is.array supplemental', () => { - assert.ok(is.array([1, 2, 3], is.number)); - assert.strictEqual(is.array([1, '2', 3], is.number), false); - - assert.doesNotThrow(() => { - isAssert.array([1, 2], isAssert.number); - }); - - assert.throws(() => { - isAssert.array([1, '2'], isAssert.number); - }); - - assert.doesNotThrow(() => { + t.notThrows(() => { const x: unknown[] = [1, 2, 3]; - isAssert.array(x, isAssert.number); + assert.array(x, assert.number); x[0]?.toFixed(0); }); - assert.doesNotThrow(() => { + t.notThrows(() => { const x: unknown[] = [1, 2, 3]; if (is.array(x, is.number)) { x[0]?.toFixed(0); } }); - assert.throws(() => { - isAssert.array([1, '2'], isAssert.number, 'Expected numbers'); - }, /Expected numbers/v); + t.throws(() => { + assert.array([1, '2'], assert.number, 'Expected numbers'); + }, {message: /Expected numbers/}); }); -test('is.arrayOf', () => { - const isStringArray = is.arrayOf(is.string); - assert.ok(isStringArray(['a', 'b', 'c'])); - assert.ok(isStringArray([])); - assert.strictEqual(isStringArray([1, 2, 3]), false); - assert.strictEqual(isStringArray(['a', 1]), false); - assert.strictEqual(isStringArray('not an array'), false); - assert.strictEqual(isStringArray(undefined), false); +test('is.boundFunction supplemental', t => { + t.false(is.boundFunction(function () {})); // eslint-disable-line prefer-arrow-callback - const isNumberArray = is.arrayOf(is.number); - assert.ok(isNumberArray([1, 2, 3])); - assert.strictEqual(isNumberArray([1, '2']), false); -}); - -test('is.oneOf', () => { - const isDirection = is.oneOf(['north', 'south', 'east', 'west'] as const); - assert.ok(isDirection('north')); - assert.ok(isDirection('west')); - assert.strictEqual(isDirection('up'), false); - assert.strictEqual(isDirection(1), false); - assert.strictEqual(isDirection(undefined), false); - - const isSmallNumber = is.oneOf([1, 2, 3] as const); - assert.ok(isSmallNumber(1)); - assert.strictEqual(isSmallNumber(4), false); - - // Empty values array always returns false - const isNever = is.oneOf([] as const); - assert.strictEqual(isNever('anything'), false); - - // Array.includes uses SameValueZero, so NaN matches NaN (unlike ===) - const isNanValue = is.oneOf([Number.NaN] as const); - assert.ok(isNanValue(Number.NaN)); -}); - -test('is.boundFunction supplemental', () => { - assert.strictEqual(is.boundFunction(function () {}), false); // eslint-disable-line prefer-arrow-callback - - assert.throws(() => { - isAssert.boundFunction(function () {}); // eslint-disable-line prefer-arrow-callback + t.throws(() => { + assert.boundFunction(function () {}); // eslint-disable-line prefer-arrow-callback }); }); -test('is.asyncFunction supplemental', () => { +test('is.asyncFunction supplemental', t => { const fixture = async () => {}; if (is.asyncFunction(fixture)) { - assert.ok(is.function(fixture().then)); + t.true(is.function(fixture().then)); - assert.doesNotThrow(() => { - isAssert.function(fixture().then); + t.notThrows(() => { + assert.function(fixture().then); }); } }); -test('is.asyncGenerator supplemental', () => { +test('is.asyncGenerator supplemental', t => { const fixture = (async function * () { yield 4; })(); if (is.asyncGenerator(fixture)) { - assert.ok(is.function(fixture.next)); + t.true(is.function(fixture.next)); } }); -test('is.asyncGeneratorFunction supplemental', () => { +test('is.asyncGeneratorFunction supplemental', t => { const fixture = async function * () { yield 4; }; if (is.asyncGeneratorFunction(fixture)) { - assert.ok(is.function(fixture().next)); + t.true(is.function(fixture().next)); } }); -test('is.enumCase', () => { +test('is.enumCase', t => { enum NonNumericalEnum { Key1 = 'key1', Key2 = 'key2', } - enum NumericKeyStringEnum { - // eslint-disable-next-line @stylistic/quote-props - '0' = 'zero', - '01' = 'padded', - } - - assert.ok(is.enumCase('key1', NonNumericalEnum)); - assert.doesNotThrow(() => { - isAssert.enumCase('key1', NonNumericalEnum); + t.true(is.enumCase('key1', NonNumericalEnum)); + t.notThrows(() => { + assert.enumCase('key1', NonNumericalEnum); }); - assert.strictEqual(is.enumCase('invalid', NonNumericalEnum), false); - assert.throws(() => { - isAssert.enumCase('invalid', NonNumericalEnum); + t.false(is.enumCase('invalid', NonNumericalEnum)); + t.throws(() => { + assert.enumCase('invalid', NonNumericalEnum); }); - - assert.ok(is.enumCase('zero', NumericKeyStringEnum)); - assert.ok(is.enumCase('padded', NumericKeyStringEnum)); - assert.doesNotThrow(() => { - isAssert.enumCase('zero', NumericKeyStringEnum); - }); - assert.doesNotThrow(() => { - isAssert.enumCase('padded', NumericKeyStringEnum); - }); - - enum NumericalEnum { - Key1 = 0, - Key2 = 1, - } - - assert.ok(is.enumCase(0, NumericalEnum)); - assert.ok(is.enumCase(1, NumericalEnum)); - assert.strictEqual(is.enumCase('Key1', NumericalEnum), false); - assert.strictEqual(is.enumCase('Key2', NumericalEnum), false); - assert.doesNotThrow(() => { - isAssert.enumCase(0, NumericalEnum); - }); - assert.throws(() => { - isAssert.enumCase('Key1', NumericalEnum); - }); - - enum HeterogeneousEnum { - A = 1, - B = 'hello', - } - - assert.ok(is.enumCase(1, HeterogeneousEnum)); - assert.ok(is.enumCase('hello', HeterogeneousEnum)); - assert.strictEqual(is.enumCase('A', HeterogeneousEnum), false); }); -test('is.directInstanceOf', () => { +test('is.directInstanceOf', t => { const error = new Error('fixture'); const errorSubclass = new ErrorSubclassFixture(); - assert.ok(is.directInstanceOf(error, Error)); - assert.ok(is.directInstanceOf(errorSubclass, ErrorSubclassFixture)); - assert.doesNotThrow(() => { - isAssert.directInstanceOf(error, Error); + t.true(is.directInstanceOf(error, Error)); + t.true(is.directInstanceOf(errorSubclass, ErrorSubclassFixture)); + t.notThrows(() => { + assert.directInstanceOf(error, Error); }); - assert.doesNotThrow(() => { - isAssert.directInstanceOf(errorSubclass, ErrorSubclassFixture); + t.notThrows(() => { + assert.directInstanceOf(errorSubclass, ErrorSubclassFixture); }); - assert.strictEqual(is.directInstanceOf(error, ErrorSubclassFixture), false); - assert.strictEqual(is.directInstanceOf(errorSubclass, Error), false); - assert.throws(() => { - isAssert.directInstanceOf(error, ErrorSubclassFixture); + t.false(is.directInstanceOf(error, ErrorSubclassFixture)); + t.false(is.directInstanceOf(errorSubclass, Error)); + t.throws(() => { + assert.directInstanceOf(error, ErrorSubclassFixture); }); - assert.throws(() => { - isAssert.directInstanceOf(errorSubclass, Error); + t.throws(() => { + assert.directInstanceOf(errorSubclass, Error); }); - assert.strictEqual(is.directInstanceOf(undefined, Error), false); - assert.strictEqual(is.directInstanceOf(null, Error), false); + t.false(is.directInstanceOf(undefined, Error)); + t.false(is.directInstanceOf(null, Error)); }); -test('is.urlInstance', () => { +test('is.urlInstance', t => { const url = new URL('https://example.com'); - assert.ok(is.urlInstance(url)); - assert.strictEqual(is.urlInstance({}), false); - assert.strictEqual(is.urlInstance(undefined), false); - assert.strictEqual(is.urlInstance(null), false); + t.true(is.urlInstance(url)); + t.false(is.urlInstance({})); + t.false(is.urlInstance(undefined)); + t.false(is.urlInstance(null)); - assert.doesNotThrow(() => { - isAssert.urlInstance(url); + t.notThrows(() => { + assert.urlInstance(url); }); - assert.throws(() => { - isAssert.urlInstance({}); + t.throws(() => { + assert.urlInstance({}); }); - assert.throws(() => { - isAssert.urlInstance(undefined); + t.throws(() => { + assert.urlInstance(undefined); }); - assert.throws(() => { - isAssert.urlInstance(null); + t.throws(() => { + assert.urlInstance(null); }); }); -test('is.urlString', () => { +test('is.urlString', t => { const url = 'https://example.com'; - assert.ok(is.urlString(url)); - assert.strictEqual(is.urlString(new URL(url)), false); - assert.strictEqual(is.urlString({}), false); - assert.strictEqual(is.urlString(undefined), false); - assert.strictEqual(is.urlString(null), false); + t.true(is.urlString(url)); + t.false(is.urlString(new URL(url))); + t.false(is.urlString({})); + t.false(is.urlString(undefined)); + t.false(is.urlString(null)); - assert.doesNotThrow(() => { - isAssert.urlString(url); + t.notThrows(() => { + assert.urlString(url); }); - assert.throws(() => { - isAssert.urlString(new URL(url)); + t.throws(() => { + assert.urlString(new URL(url)); }); - assert.throws(() => { - isAssert.urlString({}); + t.throws(() => { + assert.urlString({}); }); - assert.throws(() => { - isAssert.urlString(undefined); + t.throws(() => { + assert.urlString(undefined); }); - assert.throws(() => { - isAssert.urlString(null); + t.throws(() => { + assert.urlString(null); }); }); @@ -1067,198 +778,194 @@ test('is.urlString', () => { } })(); -// Type test for is.nan branded-type narrowing -(() => { - const value: unknown = Number.NaN; +test('is.truthy', t => { + t.true(is.truthy('unicorn')); + t.true(is.truthy('🦄')); + t.true(is.truthy(new Set())); + t.true(is.truthy(Symbol('🦄'))); + t.true(is.truthy(true)); + t.true(is.truthy(1)); + t.true(is.truthy(1n)); + t.true(is.truthy(BigInt(1))); - if (is.nan(value)) { - // ✅ In true branch: value is narrowed to the branded NaN type - expectTypeOf(value).toEqualTypeOf(); - expectTypeOf(value).toMatchTypeOf(); - } else { - // ✅ In false branch: value remains unknown (not incorrectly narrowed) - expectTypeOf(value).toEqualTypeOf(); - } -})(); - -test('is.truthy', () => { - assert.ok(is.truthy('unicorn')); - assert.ok(is.truthy('🦄')); - assert.ok(is.truthy(new Set())); - assert.ok(is.truthy(Symbol('🦄'))); - assert.ok(is.truthy(true)); - assert.ok(is.truthy(1)); - assert.ok(is.truthy(1n)); - - assert.doesNotThrow(() => { - isAssert.truthy('unicorn'); + t.notThrows(() => { + assert.truthy('unicorn'); }); - assert.doesNotThrow(() => { - isAssert.truthy('🦄'); + t.notThrows(() => { + assert.truthy('🦄'); }); - assert.doesNotThrow(() => { - isAssert.truthy(new Set()); + t.notThrows(() => { + assert.truthy(new Set()); }); - assert.doesNotThrow(() => { - isAssert.truthy(Symbol('🦄')); + t.notThrows(() => { + assert.truthy(Symbol('🦄')); }); - assert.doesNotThrow(() => { - isAssert.truthy(true); + t.notThrows(() => { + assert.truthy(true); }); - assert.doesNotThrow(() => { - isAssert.truthy(1); + t.notThrows(() => { + assert.truthy(1); }); - assert.doesNotThrow(() => { - isAssert.truthy(1n); + t.notThrows(() => { + assert.truthy(1n); }); - // Checks that `isAssert.truthy` narrow downs boolean type to `true`. + t.notThrows(() => { + assert.truthy(BigInt(1)); + }); + + // Checks that `assert.truthy` narrow downs boolean type to `true`. { const booleans = [true, false]; const function_ = (value: true) => value; - isAssert.truthy(booleans[0]); + assert.truthy(booleans[0]); function_(booleans[0]); } - // Checks that `isAssert.truthy` excludes zero value from number type. + // Checks that `assert.truthy` excludes zero value from number type. { const bits: Array<0 | 1> = [1, 0, -0]; const function_ = (value: 1) => value; - isAssert.truthy(bits[0]); + assert.truthy(bits[0]); function_(bits[0]); } - // Checks that `isAssert.truthy` excludes zero value from bigint type. + // Checks that `assert.truthy` excludes zero value from bigint type. { const bits: Array<0n | 1n> = [1n, 0n, -0n]; const function_ = (value: 1n) => value; - isAssert.truthy(bits[0]); + assert.truthy(bits[0]); function_(bits[0]); } - // Checks that `isAssert.truthy` excludes empty string from string type. + // Checks that `assert.truthy` excludes empty string from string type. { const strings: Array<'nonEmpty' | ''> = ['nonEmpty', '']; const function_ = (value: 'nonEmpty') => value; - isAssert.truthy(strings[0]); + assert.truthy(strings[0]); function_(strings[0]); } - // Checks that `isAssert.truthy` excludes undefined from mixed type. + // Checks that `assert.truthy` excludes undefined from mixed type. { const maybeUndefineds = ['🦄', undefined]; const function_ = (value: string) => value; - isAssert.truthy(maybeUndefineds[0]); + assert.truthy(maybeUndefineds[0]); function_(maybeUndefineds[0]); } - // Checks that `isAssert.truthy` excludes null from mixed type. + // Checks that `assert.truthy` excludes null from mixed type. { const maybeNulls = ['🦄', null]; const function_ = (value: string) => value; - isAssert.truthy(maybeNulls[0]); + assert.truthy(maybeNulls[0]); function_(maybeNulls[0]); } }); -test('is.falsy', () => { - assert.ok(is.falsy(false)); - assert.ok(is.falsy(0)); - assert.ok(is.falsy('')); - assert.ok(is.falsy(null)); - assert.ok(is.falsy(undefined)); - assert.ok(is.falsy(Number.NaN)); - assert.ok(is.falsy(0n)); +test('is.falsy', t => { + t.true(is.falsy(false)); + t.true(is.falsy(0)); + t.true(is.falsy('')); + t.true(is.falsy(null)); + t.true(is.falsy(undefined)); + t.true(is.falsy(Number.NaN)); + t.true(is.falsy(0n)); + t.true(is.falsy(BigInt(0))); - assert.doesNotThrow(() => { - isAssert.falsy(false); + t.notThrows(() => { + assert.falsy(false); }); - assert.doesNotThrow(() => { - isAssert.falsy(0); + t.notThrows(() => { + assert.falsy(0); }); - assert.doesNotThrow(() => { - isAssert.falsy(''); + t.notThrows(() => { + assert.falsy(''); }); - assert.doesNotThrow(() => { - isAssert.falsy(null); + t.notThrows(() => { + assert.falsy(null); }); - assert.doesNotThrow(() => { - isAssert.falsy(undefined); + t.notThrows(() => { + assert.falsy(undefined); }); - assert.doesNotThrow(() => { - isAssert.falsy(Number.NaN); + t.notThrows(() => { + assert.falsy(Number.NaN); }); - assert.doesNotThrow(() => { - isAssert.falsy(0n); + t.notThrows(() => { + assert.falsy(0n); }); - // Checks that `isAssert.falsy` narrow downs boolean type to `false`. + t.notThrows(() => { + assert.falsy(BigInt(0)); + }); + + // Checks that `assert.falsy` narrow downs boolean type to `false`. { const booleans = [false, true]; const function_ = (value?: false) => value; - isAssert.falsy(booleans[0]); + assert.falsy(booleans[0]); function_(booleans[0]); } - // Checks that `isAssert.falsy` narrow downs number type to `0`. + // Checks that `assert.falsy` narrow downs number type to `0`. { const bits = [0, -0, 1]; const function_ = (value?: 0) => value; - isAssert.falsy(bits[0]); + assert.falsy(bits[0]); function_(bits[0]); - isAssert.falsy(bits[1]); + assert.falsy(bits[1]); function_(bits[1]); } - // Checks that `isAssert.falsy` narrow downs bigint type to `0n`. + // Checks that `assert.falsy` narrow downs bigint type to `0n`. { const bits = [0n, -0n, 1n]; const function_ = (value?: 0n) => value; - isAssert.falsy(bits[0]); + assert.falsy(bits[0]); function_(bits[0]); - isAssert.falsy(bits[1]); + assert.falsy(bits[1]); function_(bits[1]); } - // Checks that `isAssert.falsy` narrow downs string type to empty string. + // Checks that `assert.falsy` narrow downs string type to empty string. { const strings = ['', 'nonEmpty']; const function_ = (value?: '') => value; - isAssert.falsy(strings[0]); + assert.falsy(strings[0]); function_(strings[0]); } - // Checks that `isAssert.falsy` can narrow down mixed type to undefined. + // Checks that `assert.falsy` can narrow down mixed type to undefined. { const maybeUndefineds = [undefined, Symbol('🦄')]; const function_ = (value: undefined) => value; - isAssert.falsy(maybeUndefineds[0]); + assert.falsy(maybeUndefineds[0]); function_(maybeUndefineds[0]); } - // Checks that `isAssert.falsy` can narrow down mixed type to null. + // Checks that `assert.falsy` can narrow down mixed type to null. { const maybeNulls = [null, Symbol('🦄')]; - // eslint-disable-next-line @typescript-eslint/no-restricted-types + // eslint-disable-next-line @typescript-eslint/ban-types const function_ = (value?: null) => value; - isAssert.falsy(maybeNulls[0]); + assert.falsy(maybeNulls[0]); function_(maybeNulls[0]); } }); -test('is.primitive', () => { +test('is.primitive', t => { const primitives: Primitive[] = [ undefined, null, @@ -1273,113 +980,113 @@ test('is.primitive', () => { ]; for (const element of primitives) { - assert.ok(is.primitive(element)); - assert.doesNotThrow(() => { - isAssert.primitive(element); + t.true(is.primitive(element)); + t.notThrows(() => { + assert.primitive(element); }); } }); -test('is.integer supplemental', () => { - assert.strictEqual(is.integer(1.4), false); - assert.throws(() => { - isAssert.integer(1.4); +test('is.integer supplemental', t => { + t.false(is.integer(1.4)); + t.throws(() => { + assert.integer(1.4); }); }); -test('is.safeInteger supplemental', () => { - assert.strictEqual(is.safeInteger(2 ** 53), false); - assert.strictEqual(is.safeInteger(-(2 ** 53)), false); - assert.throws(() => { - isAssert.safeInteger(2 ** 53); +test('is.safeInteger supplemental', t => { + t.false(is.safeInteger(2 ** 53)); + t.false(is.safeInteger(-(2 ** 53))); + t.throws(() => { + assert.safeInteger(2 ** 53); }); - assert.throws(() => { - isAssert.safeInteger(-(2 ** 53)); + t.throws(() => { + assert.safeInteger(-(2 ** 53)); }); }); -test('is.iterable', () => { - assert.ok(is.iterable('')); - assert.ok(is.iterable([])); - assert.ok(is.iterable(new Map())); - assert.strictEqual(is.iterable(null), false); - assert.strictEqual(is.iterable(undefined), false); - assert.strictEqual(is.iterable(0), false); - assert.strictEqual(is.iterable(Number.NaN), false); - assert.strictEqual(is.iterable(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.iterable({}), false); +test('is.iterable', t => { + t.true(is.iterable('')); + t.true(is.iterable([])); + t.true(is.iterable(new Map())); + t.false(is.iterable(null)); + t.false(is.iterable(undefined)); + t.false(is.iterable(0)); + t.false(is.iterable(Number.NaN)); + t.false(is.iterable(Number.POSITIVE_INFINITY)); + t.false(is.iterable({})); - assert.doesNotThrow(() => { - isAssert.iterable(''); + t.notThrows(() => { + assert.iterable(''); }); - assert.doesNotThrow(() => { - isAssert.iterable([]); + t.notThrows(() => { + assert.iterable([]); }); - assert.doesNotThrow(() => { - isAssert.iterable(new Map()); + t.notThrows(() => { + assert.iterable(new Map()); }); - assert.throws(() => { - isAssert.iterable(null); + t.throws(() => { + assert.iterable(null); }); - assert.throws(() => { - isAssert.iterable(undefined); + t.throws(() => { + assert.iterable(undefined); }); - assert.throws(() => { - isAssert.iterable(0); + t.throws(() => { + assert.iterable(0); }); - assert.throws(() => { - isAssert.iterable(Number.NaN); + t.throws(() => { + assert.iterable(Number.NaN); }); - assert.throws(() => { - isAssert.iterable(Number.POSITIVE_INFINITY); + t.throws(() => { + assert.iterable(Number.POSITIVE_INFINITY); }); - assert.throws(() => { - isAssert.iterable({}); + t.throws(() => { + assert.iterable({}); }); }); -test('is.asyncIterable', () => { - assert.ok(is.asyncIterable({ +test('is.asyncIterable', t => { + t.true(is.asyncIterable({ [Symbol.asyncIterator]() {}, })); - assert.strictEqual(is.asyncIterable(null), false); - assert.strictEqual(is.asyncIterable(undefined), false); - assert.strictEqual(is.asyncIterable(0), false); - assert.strictEqual(is.asyncIterable(Number.NaN), false); - assert.strictEqual(is.asyncIterable(Number.POSITIVE_INFINITY), false); - assert.strictEqual(is.asyncIterable({}), false); + t.false(is.asyncIterable(null)); + t.false(is.asyncIterable(undefined)); + t.false(is.asyncIterable(0)); + t.false(is.asyncIterable(Number.NaN)); + t.false(is.asyncIterable(Number.POSITIVE_INFINITY)); + t.false(is.asyncIterable({})); - assert.doesNotThrow(() => { - isAssert.asyncIterable({ + t.notThrows(() => { + assert.asyncIterable({ [Symbol.asyncIterator]() {}, }); }); - assert.throws(() => { - isAssert.asyncIterable(null); + t.throws(() => { + assert.asyncIterable(null); }); - assert.throws(() => { - isAssert.asyncIterable(undefined); + t.throws(() => { + assert.asyncIterable(undefined); }); - assert.throws(() => { - isAssert.asyncIterable(0); + t.throws(() => { + assert.asyncIterable(0); }); - assert.throws(() => { - isAssert.asyncIterable(Number.NaN); + t.throws(() => { + assert.asyncIterable(Number.NaN); }); - assert.throws(() => { - isAssert.asyncIterable(Number.POSITIVE_INFINITY); + t.throws(() => { + assert.asyncIterable(Number.POSITIVE_INFINITY); }); - assert.throws(() => { - isAssert.asyncIterable({}); + t.throws(() => { + assert.asyncIterable({}); }); }); -test('is.class', () => { +test('is.class', t => { class Foo {} // eslint-disable-line @typescript-eslint/no-extraneous-class - // Note: Using new Function to test a minified class (no whitespace in source) + // Note: Using new Function to prevent whitespace modifications in tsimp const minifiedClass = new Function('return class{};'); // eslint-disable-line no-new-func const classDeclarations = [ @@ -1389,20 +1096,19 @@ test('is.class', () => { ]; for (const classDeclaration of classDeclarations) { - assert.ok(is.class(classDeclaration)); + t.true(is.class(classDeclaration)); - assert.doesNotThrow(() => { - isAssert.class(classDeclaration); + t.notThrows(() => { + assert.class(classDeclaration); }); } }); -test('is.typedArray', () => { +test('is.typedArray', t => { const typedArrays: TypedArray[] = [ new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), - new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), @@ -1413,98 +1119,98 @@ test('is.typedArray', () => { ]; for (const item of typedArrays) { - assert.ok(is.typedArray(item)); + t.true(is.typedArray(item)); - assert.doesNotThrow(() => { - isAssert.typedArray(item); + t.notThrows(() => { + assert.typedArray(item); }); } - assert.strictEqual(is.typedArray(new ArrayBuffer(1)), false); - assert.strictEqual(is.typedArray([]), false); - assert.strictEqual(is.typedArray({}), false); + t.false(is.typedArray(new ArrayBuffer(1))); + t.false(is.typedArray([])); + t.false(is.typedArray({})); - assert.throws(() => { - isAssert.typedArray(new ArrayBuffer(1)); + t.throws(() => { + assert.typedArray(new ArrayBuffer(1)); }); - assert.throws(() => { - isAssert.typedArray([]); + t.throws(() => { + assert.typedArray([]); }); - assert.throws(() => { - isAssert.typedArray({}); + t.throws(() => { + assert.typedArray({}); }); }); -test('is.arrayLike', () => { +test('is.arrayLike', t => { (function () { - assert.ok(is.arrayLike(arguments)); // eslint-disable-line prefer-rest-params + t.true(is.arrayLike(arguments)); // eslint-disable-line prefer-rest-params })(); - assert.ok(is.arrayLike([])); - assert.ok(is.arrayLike('unicorn')); + t.true(is.arrayLike([])); + t.true(is.arrayLike('unicorn')); - assert.strictEqual(is.arrayLike({}), false); - assert.strictEqual(is.arrayLike(() => {}), false); - assert.strictEqual(is.arrayLike(new Map()), false); + t.false(is.arrayLike({})); + t.false(is.arrayLike(() => {})); + t.false(is.arrayLike(new Map())); (function () { - assert.doesNotThrow(function () { - isAssert.arrayLike(arguments); // eslint-disable-line prefer-rest-params + t.notThrows(function () { + assert.arrayLike(arguments); // eslint-disable-line prefer-rest-params }); })(); - assert.doesNotThrow(() => { - isAssert.arrayLike([]); + t.notThrows(() => { + assert.arrayLike([]); }); - assert.doesNotThrow(() => { - isAssert.arrayLike('unicorn'); + t.notThrows(() => { + assert.arrayLike('unicorn'); }); - assert.throws(() => { - isAssert.arrayLike({}); + t.throws(() => { + assert.arrayLike({}); }); - assert.throws(() => { - isAssert.arrayLike(() => {}); + t.throws(() => { + assert.arrayLike(() => {}); }); - assert.throws(() => { - isAssert.arrayLike(new Map()); + t.throws(() => { + assert.arrayLike(new Map()); }); }); -test('is.tupleLike', () => { +test('is.tupleLike', t => { (function () { - assert.strictEqual(is.tupleLike(arguments, []), false); // eslint-disable-line prefer-rest-params + t.false(is.tupleLike(arguments, [])); // eslint-disable-line prefer-rest-params })(); - assert.ok(is.tupleLike([], [])); - assert.ok(is.tupleLike([1, '2', true, {}, [], undefined, null], [is.number, is.string, is.boolean, is.object, is.array, is.undefined, is.nullOrUndefined])); - assert.strictEqual(is.tupleLike('unicorn', [is.string]), false); + t.true(is.tupleLike([], [])); + t.true(is.tupleLike([1, '2', true, {}, [], undefined, null], [is.number, is.string, is.boolean, is.object, is.array, is.undefined, is.nullOrUndefined])); + t.false(is.tupleLike('unicorn', [is.string])); - assert.strictEqual(is.tupleLike({}, []), false); - assert.strictEqual(is.tupleLike(() => {}, [is.function]), false); - assert.strictEqual(is.tupleLike(new Map(), [is.map]), false); + t.false(is.tupleLike({}, [])); + t.false(is.tupleLike(() => {}, [is.function])); + t.false(is.tupleLike(new Map(), [is.map])); (function () { - assert.throws(function () { - isAssert.tupleLike(arguments, []); // eslint-disable-line prefer-rest-params + t.throws(function () { + assert.tupleLike(arguments, []); // eslint-disable-line prefer-rest-params }); })(); - assert.doesNotThrow(() => { - isAssert.tupleLike([], []); + t.notThrows(() => { + assert.tupleLike([], []); }); - assert.throws(() => { - isAssert.tupleLike('unicorn', [is.string]); + t.throws(() => { + assert.tupleLike('unicorn', [is.string]); }); - assert.throws(() => { - isAssert.tupleLike({}, [is.object]); + t.throws(() => { + assert.tupleLike({}, [is.object]); }); - assert.throws(() => { - isAssert.tupleLike(() => {}, [is.function]); + t.throws(() => { + assert.tupleLike(() => {}, [is.function]); }); - assert.throws(() => { - isAssert.tupleLike(new Map(), [is.map]); + t.throws(() => { + assert.tupleLike(new Map(), [is.map]); }); { @@ -1530,135 +1236,127 @@ test('is.tupleLike', () => { { const tuple = [1, '1', true, null, undefined]; - if (is.tupleLike(tuple, [is.number, is.string, is.boolean, is.null, is.undefined])) { + if (is.tupleLike(tuple, [is.number, is.string, is.boolean, is.undefined, is.null])) { const numericValue = tuple[0]; const stringValue = tuple[1]; const booleanValue = tuple[2]; - const nullValue = tuple[3]; - const undefinedValue = tuple[4]; + const undefinedValue = tuple[3]; + const nullValue = tuple[4]; expectTypeOf(numericValue).toEqualTypeOf(); expectTypeOf(stringValue).toEqualTypeOf(); expectTypeOf(booleanValue).toEqualTypeOf(); - // eslint-disable-next-line @typescript-eslint/no-restricted-types - expectTypeOf(nullValue).toEqualTypeOf(); expectTypeOf(undefinedValue).toEqualTypeOf(); + // eslint-disable-next-line @typescript-eslint/ban-types + expectTypeOf(nullValue).toEqualTypeOf(); } } }); -test('is.inRange', () => { +test('is.inRange', t => { const x = 3; - assert.ok(is.inRange(x, [0, 5])); - assert.ok(is.inRange(x, [5, 0])); - assert.ok(is.inRange(x, [-5, 5])); - assert.ok(is.inRange(x, [5, -5])); - assert.strictEqual(is.inRange(x, [4, 8]), false); - assert.ok(is.inRange(-7, [-5, -10])); - assert.ok(is.inRange(-5, [-5, -10])); - assert.ok(is.inRange(-10, [-5, -10])); + t.true(is.inRange(x, [0, 5])); + t.true(is.inRange(x, [5, 0])); + t.true(is.inRange(x, [-5, 5])); + t.true(is.inRange(x, [5, -5])); + t.false(is.inRange(x, [4, 8])); + t.true(is.inRange(-7, [-5, -10])); + t.true(is.inRange(-5, [-5, -10])); + t.true(is.inRange(-10, [-5, -10])); - assert.ok(is.inRange(x, 10)); - assert.ok(is.inRange(0, 0)); - assert.ok(is.inRange(-2, -3)); - assert.strictEqual(is.inRange(x, 2), false); - assert.strictEqual(is.inRange(-3, -2), false); + t.true(is.inRange(x, 10)); + t.true(is.inRange(0, 0)); + t.true(is.inRange(-2, -3)); + t.false(is.inRange(x, 2)); + t.false(is.inRange(-3, -2)); - assert.throws(() => { + t.throws(() => { // @ts-expect-error invalid argument is.inRange(0, []); }); - assert.throws(() => { + t.throws(() => { // @ts-expect-error invalid argument is.inRange(0, [5]); }); - assert.throws(() => { + t.throws(() => { // @ts-expect-error invalid argument is.inRange(0, [1, 2, 3]); }); - assert.throws(() => { - is.inRange(5, [Number.NaN, 10]); - }, TypeError); - - assert.throws(() => { - is.inRange(5, [0, Number.NaN]); - }, TypeError); - - assert.doesNotThrow(() => { - isAssert.inRange(x, [0, 5]); + t.notThrows(() => { + assert.inRange(x, [0, 5]); }); - assert.doesNotThrow(() => { - isAssert.inRange(x, [5, 0]); + t.notThrows(() => { + assert.inRange(x, [5, 0]); }); - assert.doesNotThrow(() => { - isAssert.inRange(x, [-5, 5]); + t.notThrows(() => { + assert.inRange(x, [-5, 5]); }); - assert.doesNotThrow(() => { - isAssert.inRange(x, [5, -5]); + t.notThrows(() => { + assert.inRange(x, [5, -5]); }); - assert.throws(() => { - isAssert.inRange(x, [4, 8]); + t.throws(() => { + assert.inRange(x, [4, 8]); }); - assert.doesNotThrow(() => { - isAssert.inRange(-7, [-5, -10]); + t.notThrows(() => { + assert.inRange(-7, [-5, -10]); }); - assert.doesNotThrow(() => { - isAssert.inRange(-5, [-5, -10]); + t.notThrows(() => { + assert.inRange(-5, [-5, -10]); }); - assert.doesNotThrow(() => { - isAssert.inRange(-10, [-5, -10]); + t.notThrows(() => { + assert.inRange(-10, [-5, -10]); }); - assert.doesNotThrow(() => { - isAssert.inRange(x, 10); + t.notThrows(() => { + assert.inRange(x, 10); }); - assert.doesNotThrow(() => { - isAssert.inRange(0, 0); + t.notThrows(() => { + assert.inRange(0, 0); }); - assert.doesNotThrow(() => { - isAssert.inRange(-2, -3); + t.notThrows(() => { + assert.inRange(-2, -3); }); - assert.throws(() => { - isAssert.inRange(x, 2); + t.throws(() => { + assert.inRange(x, 2); }); - assert.throws(() => { - isAssert.inRange(-3, -2); + t.throws(() => { + assert.inRange(-3, -2); }); - assert.throws(() => { + t.throws(() => { // @ts-expect-error invalid argument - isAssert.inRange(0, []); + assert.inRange(0, []); }); - assert.throws(() => { + t.throws(() => { // @ts-expect-error invalid argument - isAssert.inRange(0, [5]); + assert.inRange(0, [5]); }); - assert.throws(() => { + t.throws(() => { // @ts-expect-error invalid argument - isAssert.inRange(0, [1, 2, 3]); + assert.inRange(0, [1, 2, 3]); }); }); -test('is.htmlElement supplemental', () => { - assert.strictEqual(is.htmlElement({nodeType: 1, nodeName: 'div'}), false); - assert.throws(() => { - isAssert.htmlElement({nodeType: 1, nodeName: 'div'}); +test('is.htmlElement supplemental', t => { + t.false(is.htmlElement({nodeType: 1, nodeName: 'div'})); + t.throws(() => { + assert.htmlElement({nodeType: 1, nodeName: 'div'}); }); const tagNames = [ @@ -1672,7 +1370,7 @@ test('is.htmlElement supplemental', () => { for (const tagName of tagNames) { const element = document.createElement(tagName); - assert.strictEqual(is(element), 'HTMLElement'); + t.is(is(element), 'HTMLElement'); } const nonHtmlElements = [ @@ -1685,57 +1383,57 @@ test('is.htmlElement supplemental', () => { ] as const; for (const element of nonHtmlElements) { - assert.throws(() => { - isAssert.htmlElement(element); + t.throws(() => { + assert.htmlElement(element); }); } }); -test('is.evenInteger', () => { +test('is.evenInteger', t => { for (const element of [-6, 2, 4]) { - assert.ok(is.evenInteger(element)); - assert.doesNotThrow(() => { - isAssert.evenInteger(element); + t.true(is.evenInteger(element)); + t.notThrows(() => { + assert.evenInteger(element); }); } for (const element of [-3, 1, 5]) { - assert.strictEqual(is.evenInteger(element), false); - assert.throws(() => { - isAssert.evenInteger(element); + t.false(is.evenInteger(element)); + t.throws(() => { + assert.evenInteger(element); }); } }); -test('is.oddInteger', () => { +test('is.oddInteger', t => { for (const element of [-5, 7, 13]) { - assert.ok(is.oddInteger(element)); - assert.doesNotThrow(() => { - isAssert.oddInteger(element); + t.true(is.oddInteger(element)); + t.notThrows(() => { + assert.oddInteger(element); }); } for (const element of [-8, 8, 10]) { - assert.strictEqual(is.oddInteger(element), false); - assert.throws(() => { - isAssert.oddInteger(element); + t.false(is.oddInteger(element)); + t.throws(() => { + assert.oddInteger(element); }); } }); -test('is.nonEmptyArray', () => { - assert.ok(is.nonEmptyArray([1, 2, 3])); - assert.strictEqual(is.nonEmptyArray([]), false); - assert.strictEqual(is.nonEmptyArray(new Array()), false); // eslint-disable-line @typescript-eslint/no-array-constructor +test('is.nonEmptyArray', t => { + t.true(is.nonEmptyArray([1, 2, 3])); + t.false(is.nonEmptyArray([])); + t.false(is.nonEmptyArray(new Array())); // eslint-disable-line @typescript-eslint/no-array-constructor - assert.doesNotThrow(() => { - isAssert.nonEmptyArray([1, 2, 3]); + t.notThrows(() => { + assert.nonEmptyArray([1, 2, 3]); }); - assert.throws(() => { - isAssert.nonEmptyArray([]); + t.throws(() => { + assert.nonEmptyArray([]); }); - assert.throws(() => { - isAssert.nonEmptyArray(new Array()); // eslint-disable-line @typescript-eslint/no-array-constructor + t.throws(() => { + assert.nonEmptyArray(new Array()); // eslint-disable-line @typescript-eslint/no-array-constructor }); { @@ -1772,7 +1470,7 @@ test('is.nonEmptyArray', () => { const strings = ['🦄', 'unicorn'] as string[] | undefined; const function_ = (value: string) => value; - isAssert.nonEmptyArray(strings); + assert.nonEmptyArray(strings); const value = strings[0]; function_(value); @@ -1782,7 +1480,7 @@ test('is.nonEmptyArray', () => { const mixed = ['🦄', 'unicorn', 1, 2]; const function_ = (value: string | number) => value; - isAssert.nonEmptyArray(mixed); + assert.nonEmptyArray(mixed); const value = mixed[0]; function_(value); @@ -1792,33 +1490,33 @@ test('is.nonEmptyArray', () => { const arrays = [['🦄'], ['unicorn']]; const function_ = (value: string[]) => value; - isAssert.nonEmptyArray(arrays); + assert.nonEmptyArray(arrays); const value = arrays[0]; function_(value); } }); -test('is.emptyString supplemental', () => { - assert.strictEqual(is.emptyString('🦄'), false); - assert.throws(() => { - isAssert.emptyString('🦄'); +test('is.emptyString supplemental', t => { + t.false(is.emptyString('🦄')); + t.throws(() => { + assert.emptyString('🦄'); }); }); -test('is.emptyStringOrWhitespace supplemental', () => { - assert.ok(is.emptyStringOrWhitespace(' ')); - assert.strictEqual(is.emptyStringOrWhitespace('🦄'), false); - assert.strictEqual(is.emptyStringOrWhitespace('unicorn'), false); +test('is.emptyStringOrWhitespace supplemental', t => { + t.true(is.emptyStringOrWhitespace(' ')); + t.false(is.emptyStringOrWhitespace('🦄')); + t.false(is.emptyStringOrWhitespace('unicorn')); - assert.doesNotThrow(() => { - isAssert.emptyStringOrWhitespace(' '); + t.notThrows(() => { + assert.emptyStringOrWhitespace(' '); }); - assert.throws(() => { - isAssert.emptyStringOrWhitespace('🦄'); + t.throws(() => { + assert.emptyStringOrWhitespace('🦄'); }); - assert.throws(() => { - isAssert.emptyStringOrWhitespace('unicorn'); + t.throws(() => { + assert.emptyStringOrWhitespace('unicorn'); }); let value = 'test'; // eslint-disable-line prefer-const -- can't use `const` here because then it will be inferred as `never` in the `if` block @@ -1829,490 +1527,343 @@ test('is.emptyStringOrWhitespace supplemental', () => { } }); -test('is.nonEmptyString', () => { - assert.strictEqual(is.nonEmptyString(''), false); - assert.strictEqual(is.nonEmptyString(String()), false); - assert.ok(is.nonEmptyString('🦄')); +test('is.nonEmptyString', t => { + t.false(is.nonEmptyString('')); + t.false(is.nonEmptyString(String())); + t.true(is.nonEmptyString('🦄')); - assert.throws(() => { - isAssert.nonEmptyString(''); + t.throws(() => { + assert.nonEmptyString(''); }); - assert.throws(() => { - isAssert.nonEmptyString(String()); + t.throws(() => { + assert.nonEmptyString(String()); }); - assert.doesNotThrow(() => { - isAssert.nonEmptyString('🦄'); + t.notThrows(() => { + assert.nonEmptyString('🦄'); }); }); -test('is.nonEmptyStringAndNotWhitespace', () => { - assert.strictEqual(is.nonEmptyStringAndNotWhitespace(' '), false); - assert.ok(is.nonEmptyStringAndNotWhitespace('🦄')); +test('is.nonEmptyStringAndNotWhitespace', t => { + t.false(is.nonEmptyStringAndNotWhitespace(' ')); + t.true(is.nonEmptyStringAndNotWhitespace('🦄')); for (const value of [null, undefined, 5, Number.NaN, {}, []]) { - assert.strictEqual(is.nonEmptyStringAndNotWhitespace(value), false); + t.false(is.nonEmptyStringAndNotWhitespace(value)); - assert.throws(() => { - isAssert.nonEmptyStringAndNotWhitespace(value); + t.throws(() => { + assert.nonEmptyStringAndNotWhitespace(value); }); } - assert.throws(() => { - isAssert.nonEmptyStringAndNotWhitespace(''); + t.throws(() => { + assert.nonEmptyStringAndNotWhitespace(''); }); - assert.doesNotThrow(() => { - isAssert.nonEmptyStringAndNotWhitespace('🦄'); + t.notThrows(() => { + assert.nonEmptyStringAndNotWhitespace('🦄'); }); }); -test('is.emptyObject', () => { - assert.ok(is.emptyObject({})); - assert.ok(is.emptyObject(new Object())); // eslint-disable-line no-object-constructor - assert.strictEqual(is.emptyObject({unicorn: '🦄'}), false); - assert.strictEqual(is.emptyObject(function () {}), false); // eslint-disable-line prefer-arrow-callback - assert.strictEqual(is.emptyObject(() => {}), false); - assert.strictEqual(is.emptyObject(class Foo {}), false); // eslint-disable-line @typescript-eslint/no-extraneous-class - assert.strictEqual(is.emptyObject([]), false); - assert.strictEqual(is.emptyObject(['unicorn']), false); +test('is.emptyObject', t => { + t.true(is.emptyObject({})); + t.true(is.emptyObject(new Object())); // eslint-disable-line no-object-constructor + t.false(is.emptyObject({unicorn: '🦄'})); - assert.doesNotThrow(() => { - isAssert.emptyObject({}); + t.notThrows(() => { + assert.emptyObject({}); }); - assert.doesNotThrow(() => { - isAssert.emptyObject(new Object()); // eslint-disable-line no-object-constructor + t.notThrows(() => { + assert.emptyObject(new Object()); // eslint-disable-line no-object-constructor }); - assert.throws(() => { - isAssert.emptyObject({unicorn: '🦄'}); - }); - assert.throws(() => { - isAssert.emptyObject(function () {}); // eslint-disable-line prefer-arrow-callback + t.throws(() => { + assert.emptyObject({unicorn: '🦄'}); }); }); -test('is.nonEmptyObject', () => { +test('is.nonEmptyObject', t => { const foo = {}; is.nonEmptyObject(foo); - assert.strictEqual(is.nonEmptyObject({}), false); - assert.strictEqual(is.nonEmptyObject(new Object()), false); // eslint-disable-line no-object-constructor - assert.ok(is.nonEmptyObject({unicorn: '🦄'})); + t.false(is.nonEmptyObject({})); + t.false(is.nonEmptyObject(new Object())); // eslint-disable-line no-object-constructor + t.true(is.nonEmptyObject({unicorn: '🦄'})); - assert.strictEqual(is.nonEmptyObject([]), false); - assert.strictEqual(is.nonEmptyObject(['unicorn']), false); - - const functionWithProperty = function () {}; - (functionWithProperty as any).custom = 'value'; - assert.strictEqual(is.nonEmptyObject(functionWithProperty), false); - - assert.throws(() => { - isAssert.nonEmptyObject({}); + t.throws(() => { + assert.nonEmptyObject({}); }); - assert.throws(() => { - isAssert.nonEmptyObject(new Object()); // eslint-disable-line no-object-constructor + t.throws(() => { + assert.nonEmptyObject(new Object()); // eslint-disable-line no-object-constructor }); - assert.doesNotThrow(() => { - isAssert.nonEmptyObject({unicorn: '🦄'}); + t.notThrows(() => { + assert.nonEmptyObject({unicorn: '🦄'}); }); }); -test('is.nonEmptySet', () => { +test('is.nonEmptySet', t => { const temporarySet = new Set(); - assert.strictEqual(is.nonEmptySet(temporarySet), false); - assert.throws(() => { - isAssert.nonEmptySet(temporarySet); + t.false(is.nonEmptySet(temporarySet)); + t.throws(() => { + assert.nonEmptySet(temporarySet); }); temporarySet.add(1); - assert.ok(is.nonEmptySet(temporarySet)); - assert.doesNotThrow(() => { - isAssert.nonEmptySet(temporarySet); + t.true(is.nonEmptySet(temporarySet)); + t.notThrows(() => { + assert.nonEmptySet(temporarySet); }); }); -test('is.nonEmptyMap', () => { +test('is.nonEmptyMap', t => { const temporaryMap = new Map(); - assert.strictEqual(is.nonEmptyMap(temporaryMap), false); - assert.throws(() => { - isAssert.nonEmptyMap(temporaryMap); + t.false(is.nonEmptyMap(temporaryMap)); + t.throws(() => { + assert.nonEmptyMap(temporaryMap); }); temporaryMap.set('unicorn', '🦄'); - assert.ok(is.nonEmptyMap(temporaryMap)); - assert.doesNotThrow(() => { - isAssert.nonEmptyMap(temporaryMap); + t.true(is.nonEmptyMap(temporaryMap)); + t.notThrows(() => { + assert.nonEmptyMap(temporaryMap); }); }); -test('is.propertyKey', () => { - assert.ok(is.propertyKey('key')); - assert.ok(is.propertyKey(42)); - assert.ok(is.propertyKey(Symbol(''))); +test('is.propertyKey', t => { + t.true(is.propertyKey('key')); + t.true(is.propertyKey(42)); + t.true(is.propertyKey(Symbol(''))); - assert.strictEqual(is.propertyKey(null), false); - assert.strictEqual(is.propertyKey(undefined), false); - assert.strictEqual(is.propertyKey(true), false); - assert.strictEqual(is.propertyKey({}), false); - assert.strictEqual(is.propertyKey([]), false); - assert.strictEqual(is.propertyKey(new Map()), false); - assert.strictEqual(is.propertyKey(new Set()), false); - - // AssertPropertyKey should narrow to PropertyKey (string | number | symbol), not just number - const symbolValue: unknown = Symbol('test'); - assertPropertyKey(symbolValue); - expectTypeOf(symbolValue).toEqualTypeOf(); + t.false(is.propertyKey(null)); + t.false(is.propertyKey(undefined)); + t.false(is.propertyKey(true)); + t.false(is.propertyKey({})); + t.false(is.propertyKey([])); + t.false(is.propertyKey(new Map())); + t.false(is.propertyKey(new Set())); }); -test('is.any', () => { - assert.ok(is.any(is.string, {}, true, '🦄')); - assert.ok(is.any(is.object, false, {}, 'unicorns')); - assert.strictEqual(is.any(is.boolean, '🦄', [], 3), false); - assert.strictEqual(is.any(is.integer, true, 'lol', {}), false); - assert.ok(is.any([is.string, is.number], {}, true, '🦄')); - assert.strictEqual(is.any([is.boolean, is.number], 'unicorns', [], new Map()), false); - assert.strictEqual(typeof is.any([is.string, is.number]), 'function'); +test('is.any', t => { + t.true(is.any(is.string, {}, true, '🦄')); + t.true(is.any(is.object, false, {}, 'unicorns')); + t.false(is.any(is.boolean, '🦄', [], 3)); + t.false(is.any(is.integer, true, 'lol', {})); + t.true(is.any([is.string, is.number], {}, true, '🦄')); + t.false(is.any([is.boolean, is.number], 'unicorns', [], new Map())); - assert.throws(() => { + t.throws(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument is.any(null as any, true); }); - assert.throws(() => { - is.any([], 'value'); - }); - - assert.throws(() => { + t.throws(() => { is.any(is.string); }); - assert.doesNotThrow(() => { - isAssert.any(is.string, {}, true, '🦄'); + t.notThrows(() => { + assert.any(is.string, {}, true, '🦄'); }); - assert.doesNotThrow(() => { - isAssert.any(is.object, false, {}, 'unicorns'); + t.notThrows(() => { + assert.any(is.object, false, {}, 'unicorns'); }); - assert.throws(() => { - isAssert.any([is.string, is.number]); + t.throws(() => { + assert.any(is.boolean, '🦄', [], 3); }); - assert.throws(() => { - isAssert.any(is.boolean, '🦄', [], 3); + t.throws(() => { + assert.any(is.integer, true, 'lol', {}); }); - assert.throws(() => { - isAssert.any(is.integer, true, 'lol', {}); + t.throws(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + assert.any(null as any, true); }); - assert.throws(() => { - isAssert.any(null as any, true); + t.throws(() => { + assert.any(is.string); }); - assert.throws(() => { - isAssert.any([], 'value'); - }); - - assert.throws(() => { - isAssert.any(is.string); - }); - - assert.throws(() => { - isAssert.any(is.string, 1, 2, 3); + t.throws(() => { + assert.any(is.string, 1, 2, 3); }, { // Includes expected type and removes duplicates from received types: - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `string`. Received values of type `number`.', 'v'), + message: /Expected values which are `string`. Received values of type `number`./, }); - assert.throws(() => { - isAssert.any(is.string, 1, [4]); + t.throws(() => { + assert.any(is.string, 1, [4]); }, { // Includes expected type and lists all received types: - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `string`. Received values of types `number` and `Array`.', 'v'), + message: /Expected values which are `string`. Received values of types `number` and `Array`./, }); - assert.throws(() => { - isAssert.any([is.string, is.nullOrUndefined], 1); + t.throws(() => { + assert.any([is.string, is.nullOrUndefined], 1); }, { // Handles array as first argument: - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `string` or `null or undefined`. Received values of type `number`.', 'v'), + message: /Expected values which are `string` or `null or undefined`. Received values of type `number`./, }); - assert.throws(() => { - isAssert.any([is.string, is.number, is.boolean], null, undefined, Number.NaN); + t.throws(() => { + assert.any([is.string, is.number, is.boolean], null, undefined, Number.NaN); }, { // Handles more than 2 expected and received types: - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `string`, `number`, or `boolean`. Received values of types `null`, `undefined`, and `NaN`.', 'v'), + message: /Expected values which are `string`, `number`, or `boolean`. Received values of types `null`, `undefined`, and `NaN`./, }); - assert.throws(() => { - isAssert.any(() => false, 1); + t.throws(() => { + assert.any(() => false, 1); }, { // Default type assertion message - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `predicate returns truthy for any value`.', 'v'), + message: /Expected values which are `predicate returns truthy for any value`./, }); }); -test('is.all', () => { - assert.ok(is.all(is.object, {}, new Set(), new Map())); - assert.ok(is.all(is.boolean, true, false)); - assert.strictEqual(is.all(is.string, '🦄', []), false); - assert.strictEqual(is.all(is.set, new Map(), {}), false); +test('is.all', t => { + t.true(is.all(is.object, {}, new Set(), new Map())); + t.true(is.all(is.boolean, true, false)); + t.false(is.all(is.string, '🦄', [])); + t.false(is.all(is.set, new Map(), {})); - assert.ok(is.all(is.array, ['1'], ['2'])); - assert.ok(is.all([is.string, is.nonEmptyString], '🦄', 'unicorns')); - assert.strictEqual(is.all([is.string, is.number], '🦄'), false); + t.true(is.all(is.array, ['1'], ['2'])); - assert.throws(() => { + t.throws(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument is.all(null as any, true); }); - assert.throws(() => { - is.all([], 'value'); - }); - - assert.throws(() => { + t.throws(() => { is.all(is.string); }); - assert.doesNotThrow(() => { - isAssert.all(is.object, {}, new Set(), new Map()); + t.notThrows(() => { + assert.all(is.object, {}, new Set(), new Map()); }); - assert.doesNotThrow(() => { - isAssert.all(is.boolean, true, false); + t.notThrows(() => { + assert.all(is.boolean, true, false); }); - assert.throws(() => { - isAssert.all([is.string, is.number]); + t.throws(() => { + assert.all(is.string, '🦄', []); }); - assert.doesNotThrow(() => { - isAssert.all([is.string, is.nonEmptyString], '🦄', 'unicorns'); + t.throws(() => { + assert.all(is.set, new Map(), {}); }); - assert.throws(() => { - isAssert.all(is.string, '🦄', []); + t.throws(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + assert.all(null as any, true); }); - assert.throws(() => { - isAssert.all([is.string, is.number], '🦄'); + t.throws(() => { + assert.all(is.string); }); - assert.throws(() => { - isAssert.all(is.set, new Map(), {}); - }); - - assert.throws(() => { - isAssert.all(null as any, true); - }); - - assert.throws(() => { - isAssert.all([], 'value'); - }); - - assert.throws(() => { - isAssert.all(is.string); - }); - - assert.throws(() => { - isAssert.all(is.string, 1, 2, 3); + t.throws(() => { + assert.all(is.string, 1, 2, 3); }, { // Includes expected type and removes duplicates from received types: - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `string`. Received values of type `number`.', 'v'), + message: /Expected values which are `string`. Received values of type `number`./, }); - assert.throws(() => { - isAssert.all(is.string, 1, [4]); + t.throws(() => { + assert.all(is.string, 1, [4]); }, { // Includes expected type and lists all received types: - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `string`. Received values of types `number` and `Array`.', 'v'), + message: /Expected values which are `string`. Received values of types `number` and `Array`./, }); - assert.throws(() => { - isAssert.all(() => false, 1); + t.throws(() => { + assert.all(() => false, 1); }, { // Default type assertion message - // eslint-disable-next-line prefer-regex-literals - message: new RegExp('Expected values which are `predicate returns truthy for all values`.', 'v'), + message: /Expected values which are `predicate returns truthy for all values`./, }); }); -test('is.any as predicate factory', () => { - // Returns a type guard function when called with only predicates - const isStringOrNumber = is.any([is.string, is.number]); - assert.strictEqual(typeof isStringOrNumber, 'function'); - assert.ok(isStringOrNumber('hello')); - assert.ok(isStringOrNumber(123)); - assert.strictEqual(isStringOrNumber(true), false); - assert.strictEqual(isStringOrNumber({}), false); - - // Type narrowing works correctly (compile-time check) - const value: unknown = 'test'; - if (isStringOrNumber(value)) { - // TypeScript should narrow to string | number - const narrowed: string | number = value; - assert.ok(typeof narrowed === 'string' || typeof narrowed === 'number'); - } - - // Works with is.optional - assert.ok(is.optional(undefined, is.any([is.string, is.number]))); - assert.ok(is.optional('test', is.any([is.string, is.number]))); - assert.ok(is.optional(42, is.any([is.string, is.number]))); - assert.strictEqual(is.optional(true, is.any([is.string, is.number])), false); - - const predicateArray: Predicate[] = [is.string, is.number]; - const isStringOrNumberFromArray = is.any(predicateArray); - assert.strictEqual(typeof isStringOrNumberFromArray, 'function'); - assert.ok(isStringOrNumberFromArray('hello')); - assert.ok(isStringOrNumberFromArray(123)); - assert.strictEqual(isStringOrNumberFromArray(true), false); - - // Type narrowing with is.optional (compile-time check) - const optionalValue: unknown = undefined; - if (is.optional(optionalValue, is.any([is.string, is.number]))) { - // TypeScript should narrow to string | number | undefined - const narrowed: string | number | undefined = optionalValue; - assert.ok(narrowed === undefined || typeof narrowed === 'string' || typeof narrowed === 'number'); - } - - // Works with more predicates - const isStringOrNumberOrBoolean = is.any([is.string, is.number, is.boolean]); - assert.ok(isStringOrNumberOrBoolean('hello')); - assert.ok(isStringOrNumberOrBoolean(123)); - assert.ok(isStringOrNumberOrBoolean(true)); - assert.strictEqual(isStringOrNumberOrBoolean({}), false); - - assert.throws(() => { - is.any([is.string, 123 as any]); - }); -}); - -test('is.all as predicate factory', () => { - // Returns a type guard function when called with only predicates - const isArrayAndNonEmpty = is.all([is.array, is.nonEmptyArray]); - assert.strictEqual(typeof isArrayAndNonEmpty, 'function'); - assert.ok(isArrayAndNonEmpty(['hello'])); - assert.strictEqual(isArrayAndNonEmpty([]), false); - assert.strictEqual(isArrayAndNonEmpty('hello'), false); - - // Type narrowing works correctly - const value: unknown = ['test']; - if (isArrayAndNonEmpty(value)) { - // TypeScript should narrow to the intersection type - assert.ok(Array.isArray(value)); - assert.ok(value.length > 0); - } - - // Works with is.optional - assert.ok(is.optional(undefined, is.all([is.object, is.plainObject]))); - assert.ok(is.optional({foo: 'bar'}, is.all([is.object, is.plainObject]))); - assert.strictEqual(is.optional([], is.all([is.object, is.plainObject])), false); - - assert.throws(() => { - is.all([is.string, 123 as any]); - }); -}); - -test('is.formData supplemental', () => { +test('is.formData supplemental', t => { const data = new window.FormData(); - assert.ok(is.formData(data)); - assert.strictEqual(is.formData({}), false); - assert.strictEqual(is.formData(undefined), false); - assert.strictEqual(is.formData(null), false); + t.true(is.formData(data)); + t.false(is.formData({})); + t.false(is.formData(undefined)); + t.false(is.formData(null)); - assert.doesNotThrow(() => { - isAssert.formData(data); + t.notThrows(() => { + assert.formData(data); }); - assert.throws(() => { - isAssert.formData({}); + t.throws(() => { + assert.formData({}); }); - assert.throws(() => { - isAssert.formData(undefined); + t.throws(() => { + assert.formData(undefined); }); - assert.throws(() => { - isAssert.formData(null); + t.throws(() => { + assert.formData(null); }); }); -test('is.urlSearchParams', () => { +test('is.urlSearchParams', t => { const searchParameters = new URLSearchParams(); - assert.ok(is.urlSearchParams(searchParameters)); - assert.strictEqual(is.urlSearchParams({}), false); - assert.strictEqual(is.urlSearchParams(undefined), false); - assert.strictEqual(is.urlSearchParams(null), false); + t.true(is.urlSearchParams(searchParameters)); + t.false(is.urlSearchParams({})); + t.false(is.urlSearchParams(undefined)); + t.false(is.urlSearchParams(null)); - assert.doesNotThrow(() => { - isAssert.urlSearchParams(searchParameters); + t.notThrows(() => { + assert.urlSearchParams(searchParameters); }); - assert.throws(() => { - isAssert.urlSearchParams({}); + t.throws(() => { + assert.urlSearchParams({}); }); - assert.throws(() => { - isAssert.urlSearchParams(undefined); + t.throws(() => { + assert.urlSearchParams(undefined); }); - assert.throws(() => { - isAssert.urlSearchParams(null); + t.throws(() => { + assert.urlSearchParams(null); }); }); -test('is.validDate', () => { - assert.ok(is.validDate(new Date())); - assert.strictEqual(is.validDate(new Date('x')), false); - assert.doesNotThrow(() => { - isAssert.validDate(new Date()); +test('is.validDate', t => { + t.true(is.validDate(new Date())); + t.false(is.validDate(new Date('x'))); + t.notThrows(() => { + assert.validDate(new Date()); }); - assert.throws(() => { - isAssert.validDate(new Date('x')); + t.throws(() => { + assert.validDate(new Date('x')); }); }); -test('is.validLength', () => { - assert.ok(is.validLength(1)); - assert.ok(is.validLength(0)); - assert.strictEqual(is.validLength(-1), false); - assert.strictEqual(is.validLength(0.1), false); - assert.doesNotThrow(() => { - isAssert.validLength(1); +test('is.validLength', t => { + t.true(is.validLength(1)); + t.true(is.validLength(0)); + t.false(is.validLength(-1)); + t.false(is.validLength(0.1)); + t.notThrows(() => { + assert.validLength(1); }); - assert.throws(() => { - isAssert.validLength(-1); - }); - assert.throws(() => { - isAssert.validLength(0.1); + t.throws(() => { + assert.validLength(-1); }); }); -test('is.whitespaceString', () => { - assert.ok(is.whitespaceString(' ')); - assert.ok(is.whitespaceString(' ')); - assert.ok(is.whitespaceString('   ')); - assert.ok(is.whitespaceString('\u3000')); - assert.ok(is.whitespaceString(' ')); - assert.strictEqual(is.whitespaceString(''), false); - assert.strictEqual(is.whitespaceString('-'), false); - assert.strictEqual(is.whitespaceString(' hi '), false); - - assert.doesNotThrow(() => { - isAssert.whitespaceString(' '); - }); - assert.throws(() => { - isAssert.whitespaceString(''); - }); - assert.throws(() => { - isAssert.whitespaceString(' hi '); - }); +test('is.whitespaceString', t => { + t.true(is.whitespaceString(' ')); + t.true(is.whitespaceString(' ')); + t.true(is.whitespaceString('   ')); + t.true(is.whitespaceString('\u3000')); + t.true(is.whitespaceString(' ')); + t.false(is.whitespaceString('')); + t.false(is.whitespaceString('-')); + t.false(is.whitespaceString(' hi ')); }); -test('assert', () => { - // Contrived test showing that TypeScript acknowledges the type assertion in `isAssert.number()`. - // Real-world usage includes asserting user input, but here we use a random number/string generator. +test('assert', t => { + // Contrived test showing that TypeScript acknowledges the type assertion in `assert.number()`. + // Real--world usage includes asserting user input, but here we use a random number/string generator. + t.plan(2); const getNumberOrStringRandomly = (): number | string => { const random = Math.random(); @@ -2326,7 +1877,7 @@ test('assert', () => { const canUseOnlyNumber = (badlyTypedArgument: any): number => { // Narrow the type to number, or throw an error at runtime for non-numbers. - isAssert.number(badlyTypedArgument); + assert.number(badlyTypedArgument); // Both the type and runtime value is number. return 1000 * badlyTypedArgument; @@ -2334,489 +1885,398 @@ test('assert', () => { const badlyTypedVariable: any = getNumberOrStringRandomly(); - assert.ok(is.number(badlyTypedVariable) || is.string(badlyTypedVariable)); + t.true(is.number(badlyTypedVariable) || is.string(badlyTypedVariable)); // Using try/catch for test purposes only. try { const result = canUseOnlyNumber(badlyTypedVariable); // Got lucky, the input was a number yielding a good result. - assert.ok(is.number(result)); + t.true(is.number(result)); } catch { // Assertion was tripped. - assert.ok(is.string(badlyTypedVariable)); + t.true(is.string(badlyTypedVariable)); } }); -test('custom assertion message', () => { +test('custom assertion message', t => { const message = 'Custom error message'; - const assertThrowsTypeErrorWithMessage = (assertion: () => void) => { - // `node:assert` does not verify the error class when matching only on `{message}`. - assert.throws(assertion, error => { - assert.ok(error instanceof TypeError); - assert.strictEqual(error.message, message); - return true; - }); - }; + t.throws(() => { + assert.array(undefined, undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.array(undefined, undefined, message); - }); + t.throws(() => { + assert.arrayBuffer(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.arrayBuffer(undefined, message); - }); + t.throws(() => { + assert.arrayLike(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.arrayLike(undefined, message); - }); + t.throws(() => { + assert.asyncFunction(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.asyncFunction(undefined, message); - }); + t.throws(() => { + assert.asyncGenerator(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.asyncGenerator(undefined, message); - }); + t.throws(() => { + assert.asyncGeneratorFunction(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.asyncGeneratorFunction(undefined, message); - }); + t.throws(() => { + assert.asyncIterable(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.asyncIterable(undefined, message); - }); + t.throws(() => { + assert.bigInt64Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.bigInt64Array(undefined, message); - }); + t.throws(() => { + assert.bigUint64Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.bigUint64Array(undefined, message); - }); + t.throws(() => { + assert.bigint(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.bigint(undefined, message); - }); + t.throws(() => { + assert.blob(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.blob(undefined, message); - }); + t.throws(() => { + assert.boolean(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.boolean(undefined, message); - }); + t.throws(() => { + assert.boundFunction(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.boundFunction(undefined, message); - }); + t.throws(() => { + assert.buffer(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.buffer(undefined, message); - }); + t.throws(() => { + assert.class(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.class(undefined, message); - }); + t.throws(() => { + assert.dataView(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.dataView(undefined, message); - }); + t.throws(() => { + assert.date(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.date(undefined, message); - }); + t.throws(() => { + assert.directInstanceOf(undefined, Error, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.directInstanceOf(undefined, Error, message); - }); + t.throws(() => { + assert.emptyArray(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.emptyArray(undefined, message); - }); + t.throws(() => { + assert.emptyMap(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.emptyMap(undefined, message); - }); + t.throws(() => { + assert.emptyObject(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.emptyObject(undefined, message); - }); + t.throws(() => { + assert.emptySet(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.emptySet(undefined, message); - }); + t.throws(() => { + assert.emptyString(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.emptyString(undefined, message); - }); + t.throws(() => { + assert.emptyStringOrWhitespace(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.emptyStringOrWhitespace(undefined, message); - }); - - assertThrowsTypeErrorWithMessage(() => { + t.throws(() => { enum Enum {} - isAssert.enumCase('invalid', Enum, message); - }); + assert.enumCase('invalid', Enum, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.error(undefined, message); - }); + t.throws(() => { + assert.error(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.evenInteger(33, message); - }); + t.throws(() => { + assert.evenInteger(33, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.falsy(true, message); - }); + t.throws(() => { + assert.falsy(true, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.finiteNumber(Number.POSITIVE_INFINITY, message); - }); + t.throws(() => { + assert.float32Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.float32Array(undefined, message); - }); + t.throws(() => { + assert.float64Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.float64Array(undefined, message); - }); + t.throws(() => { + assert.formData(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.formData(undefined, message); - }); + t.throws(() => { + assert.function(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.function(undefined, message); - }); + t.throws(() => { + assert.generator(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.generator(undefined, message); - }); + t.throws(() => { + assert.generatorFunction(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.generatorFunction(undefined, message); - }); + t.throws(() => { + assert.htmlElement(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.htmlElement(undefined, message); - }); + t.throws(() => { + assert.inRange(5, [1, 2], message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.inRange(5, [1, 2], message); - }); + t.throws(() => { + assert.infinite(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.infinite(undefined, message); - }); + t.throws(() => { + assert.int16Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.int16Array(undefined, message); - }); + t.throws(() => { + assert.int32Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.int32Array(undefined, message); - }); + t.throws(() => { + assert.int8Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.int8Array(undefined, message); - }); + t.throws(() => { + assert.integer(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.integer(undefined, message); - }); + t.throws(() => { + assert.iterable(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.iterable(undefined, message); - }); + t.throws(() => { + assert.map(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.map(undefined, message); - }); + t.throws(() => { + assert.nan(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nan(undefined, message); - }); + t.throws(() => { + assert.nativePromise(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nativePromise(undefined, message); - }); + t.throws(() => { + assert.negativeNumber(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.not.undefined(undefined, message); - }); + t.throws(() => { + assert.nodeStream(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.not.string('hello', message); - }); + t.throws(() => { + assert.nonEmptyArray(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.negativeNumber(undefined, message); - }); + t.throws(() => { + assert.nonEmptyMap(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nodeStream(undefined, message); - }); + t.throws(() => { + assert.nonEmptyObject(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonEmptyArray(undefined, message); - }); + t.throws(() => { + assert.nonEmptySet(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonEmptyMap(undefined, message); - }); + t.throws(() => { + assert.nonEmptyString(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonEmptyObject(undefined, message); - }); + t.throws(() => { + assert.nonEmptyStringAndNotWhitespace(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonEmptySet(undefined, message); - }); + t.throws(() => { + assert.null(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonEmptyString(undefined, message); - }); + t.throws(() => { + assert.nullOrUndefined(false, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonEmptyStringAndNotWhitespace(undefined, message); - }); + t.throws(() => { + assert.number(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nonNegativeNumber(-1, message); - }); + t.throws(() => { + assert.numericString(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.null(undefined, message); - }); + t.throws(() => { + assert.object(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.nullOrUndefined(false, message); - }); + t.throws(() => { + assert.observable(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.number(undefined, message); - }); + t.throws(() => { + assert.oddInteger(42, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.numericString(undefined, message); - }); + t.throws(() => { + assert.plainObject(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.object(undefined, message); - }); + t.throws(() => { + assert.positiveNumber(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.observable(undefined, message); - }); + t.throws(() => { + assert.primitive([], message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.oddInteger(42, message); - }); + t.throws(() => { + assert.promise(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.plainObject(undefined, message); - }); + t.throws(() => { + assert.propertyKey(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.positiveInteger(0, message); - }); + t.throws(() => { + assert.regExp(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.positiveNumber(undefined, message); - }); + t.throws(() => { + assert.safeInteger(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.primitive([], message); - }); + t.throws(() => { + assert.set(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.promise(undefined, message); - }); + t.throws(() => { + assert.sharedArrayBuffer(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.propertyKey(undefined, message); - }); + t.throws(() => { + assert.string(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.regExp(undefined, message); - }); + t.throws(() => { + assert.symbol(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.safeInteger(undefined, message); - }); + t.throws(() => { + assert.truthy(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.set(undefined, message); - }); + t.throws(() => { + assert.tupleLike(undefined, [], message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.sharedArrayBuffer(undefined, message); - }); + t.throws(() => { + assert.typedArray(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.string(undefined, message); - }); + t.throws(() => { + assert.uint16Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.symbol(undefined, message); - }); + t.throws(() => { + assert.uint32Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.truthy(undefined, message); - }); + t.throws(() => { + assert.uint8Array(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.tupleLike(undefined, [], message); - }); + t.throws(() => { + assert.uint8ClampedArray(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.typedArray(undefined, message); - }); + t.throws(() => { + assert.undefined(false, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.uint16Array(undefined, message); - }); + t.throws(() => { + assert.urlInstance(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.uint32Array(undefined, message); - }); + t.throws(() => { + assert.urlSearchParams(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.uint8Array(undefined, message); - }); + t.throws(() => { + assert.urlString(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.uint8ClampedArray(undefined, message); - }); + t.throws(() => { + assert.validDate(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.undefined(false, message); - }); + t.throws(() => { + assert.validLength(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.urlInstance(undefined, message); - }); + t.throws(() => { + assert.weakMap(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.urlSearchParams(undefined, message); - }); + t.throws(() => { + assert.weakRef(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.urlString(undefined, message); - }); + t.throws(() => { + assert.weakSet(undefined, message); + }, {instanceOf: TypeError, message}); - assertThrowsTypeErrorWithMessage(() => { - isAssert.validDate(undefined, message); - }); - - assertThrowsTypeErrorWithMessage(() => { - isAssert.validLength(undefined, message); - }); - - assertThrowsTypeErrorWithMessage(() => { - isAssert.weakMap(undefined, message); - }); - - assertThrowsTypeErrorWithMessage(() => { - isAssert.weakRef(undefined, message); - }); - - assertThrowsTypeErrorWithMessage(() => { - isAssert.weakSet(undefined, message); - }); - - assertThrowsTypeErrorWithMessage(() => { - isAssert.whitespaceString(undefined, message); - }); + t.throws(() => { + assert.whitespaceString(undefined, message); + }, {instanceOf: TypeError, message}); }); -test('isAssert.not.undefined', () => { - assert.throws(() => { - isAssert.not.undefined(undefined); - }, { - message: 'Expected value which is not `undefined`, received value of type `undefined`.', - }); - - assert.doesNotThrow(() => { - isAssert.not.undefined(null); - }); - - assert.doesNotThrow(() => { - isAssert.not.undefined(false); - }); - - assert.doesNotThrow(() => { - isAssert.not.undefined(0); - }); - - assert.doesNotThrow(() => { - isAssert.not.undefined(''); - }); +test('is.optional', t => { + t.true(is.optional(undefined, is.string)); + t.true(is.optional('🦄', is.string)); + t.false(is.optional(123, is.string)); + t.false(is.optional(null, is.string)); }); -test('isAssert.not', () => { - assert.deepStrictEqual(new Set(keysOf(isAssert.not)), new Set(keysOf(notAssertionFixtures))); +test('assert.optional', t => { + t.notThrows(() => { + assert.optional(undefined, assert.string); + }); - for (const type of keysOf(notAssertionFixtures)) { - const {nonFixture, typeDescription} = notAssertionFixtures[type]; - const testAssert = isAssert.not[type]; - const fixtures = 'fixtures' in notAssertionFixtures[type] ? notAssertionFixtures[type].fixtures : [notAssertionFixtures[type].fixture]; + t.notThrows(() => { + assert.optional('🦄', assert.string); + }); - for (const fixture of fixtures) { - assert.throws(() => { - testAssert(fixture); - }, { - message: `Expected value which is not \`${typeDescription}\`, received value of type \`${is(fixture)}\`.`, - }); - } + t.throws(() => { + assert.optional(123, assert.string); + }); - assert.doesNotThrow(() => { - testAssert(nonFixture); - }); - } - - assert.strictEqual('number' in isAssert.not, false); - assert.strictEqual('integer' in isAssert.not, false); - assert.strictEqual('object' in isAssert.not, false); - assert.strictEqual('blob' in isAssert.not, false); - assert.strictEqual('array' in isAssert.not, false); - assert.strictEqual('date' in isAssert.not, false); - assert.strictEqual('function' in isAssert.not, false); - assert.strictEqual('map' in isAssert.not, false); - assert.strictEqual('set' in isAssert.not, false); -}); - -test('isAssert.not edge cases', () => { - assert.doesNotThrow(() => { - isAssert.not.null(undefined); - }); -}); - -test('is.optional', () => { - assert.ok(is.optional(undefined, is.string)); - assert.ok(is.optional('🦄', is.string)); - assert.strictEqual(is.optional(123, is.string), false); - assert.strictEqual(is.optional(null, is.string), false); -}); - -test('isAssert.optional', () => { - assert.doesNotThrow(() => { - isAssert.optional(undefined, isAssert.string); - }); - - assert.doesNotThrow(() => { - isAssert.optional('🦄', isAssert.string); - }); - - assert.throws(() => { - isAssert.optional(123, isAssert.string); - }); - - assert.throws(() => { - isAssert.optional(null, isAssert.string); + t.throws(() => { + assert.optional(null, assert.string); }); }); diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index 1f492d3..0000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "rootDir": "..", - "noUnusedLocals": false, - "noUnusedParameters": false - }, - "include": [ - "../source", - "type-tests.ts" - ] -} diff --git a/test/type-tests.ts b/test/type-tests.ts deleted file mode 100644 index f08fa25..0000000 --- a/test/type-tests.ts +++ /dev/null @@ -1,405 +0,0 @@ -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 = Exclude | 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` = `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(); -}; - -const assertNotUndefinedUnknownCheck = (value: unknown) => { - isAssert.not.undefined(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotUndefinedGenericCheck = (value: T) => { - isAssert.not.undefined(value); - const _: Exclude = value; -}; - -const nullValue = null; -type Null = typeof nullValue; - -const assertNotNullUnknownCheck = (value: unknown) => { - isAssert.not.null(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotNullOrUndefinedCheck = (value: string | Null | undefined) => { - isAssert.not.nullOrUndefined(value); - expectTypeOf(value).toEqualTypeOf(); -}; - -const assertNotNullOrUndefinedUnknownCheck = (value: unknown) => { - isAssert.not.nullOrUndefined(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotStringCheck = (value: string | number) => { - isAssert.not.string(value); - expectTypeOf(value).toEqualTypeOf(); -}; - -const assertNotStringUnknownCheck = (value: unknown) => { - isAssert.not.string(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotStringGenericCheck = (value: T) => { - isAssert.not.string(value); - const _: Exclude = value; -}; - -const assertNotBooleanUnknownCheck = (value: unknown) => { - isAssert.not.boolean(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotSymbolUnknownCheck = (value: unknown) => { - isAssert.not.symbol(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotBigintUnknownCheck = (value: unknown) => { - isAssert.not.bigint(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotPrimitiveUnknownCheck = (value: unknown) => { - isAssert.not.primitive(value); - // eslint-disable-next-line @typescript-eslint/no-restricted-types - expectTypeOf(value).toEqualTypeOf(); -}; - -const assertNotPrimitiveGenericCheck = (value: T) => { - isAssert.not.primitive(value); - const _: Exclude = 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>(); -}; - -const assertNotNamedStringExportCheck = (value: string | number) => { - assertNotString(value); - expectTypeOf(value).toEqualTypeOf(); -}; - -const assertNotNamedStringUnknownExportCheck = (value: unknown) => { - assertNotString(value); - expectTypeOf(value).toEqualTypeOf>(); -}; - -const assertNotNamedPrimitiveUnknownExportCheck = (value: unknown) => { - assertNotPrimitive(value); - // eslint-disable-next-line @typescript-eslint/no-restricted-types - expectTypeOf(value).toEqualTypeOf(); -}; - -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) => { - // @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 = 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) => { - // @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 = value; -}; - -const assertNotSetDoesNotExistCheck = (value: Set | 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 = 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('🦄'); -assertNotNullUnknownCheck('🦄'); -assertNotNullOrUndefinedCheck('🦄'); -assertNotNullOrUndefinedUnknownCheck('🦄'); -assertNotStringCheck(1); -assertNotStringUnknownCheck(1); -assertNotStringGenericCheck(1); -assertNotBooleanUnknownCheck(1); -assertNotSymbolUnknownCheck(1); -assertNotBigintUnknownCheck(1); -assertNotPrimitiveUnknownCheck({}); -assertNotPrimitiveGenericCheck({unicorn: true}); -assertNotNamedUndefinedExportCheck(0); -assertNotNamedNullOrUndefinedUnknownExportCheck('🦄'); -assertNotNamedStringExportCheck(1); -assertNotNamedStringUnknownExportCheck(1); -assertNotNamedPrimitiveUnknownExportCheck({}); -assertNotCallableDoesNotExistCheck('🦄'); -assertNotNumberDoesNotExistCheck(Number.NaN); -assertNotIntegerDoesNotExistCheck(1.5); -assertNotObjectDoesNotExistCheck('🦄'); -assertNotBlobDoesNotExistCheck('🦄'); -assertNotMapDoesNotExistCheck('🦄'); -assertNotSetDoesNotExistCheck('🦄'); -assertNotDateDoesNotExistCheck('🦄'); diff --git a/tsconfig.json b/tsconfig.json index 46013a6..0aace6f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,5 @@ { "extends": "@sindresorhus/tsconfig", - "compilerOptions": { - "types": ["node"], - "rootDir": "source", - "allowImportingTsExtensions": true, - "rewriteRelativeImportExtensions": true - }, "include": [ "source" ],