Compare commits
No commits in common. "main" and "v7.2.0" have entirely different histories.
12 changed files with 1102 additions and 2393 deletions
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
|
|
@ -10,11 +10,10 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node-version:
|
node-version:
|
||||||
- 24
|
- 20
|
||||||
- 22
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: npm install
|
- run: npm install
|
||||||
|
|
|
||||||
|
|
@ -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<number, number>` = `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, Integer>` = `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`.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
AGENTS.md
|
|
||||||
47
package.json
47
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sindresorhus/is",
|
"name": "@sindresorhus/is",
|
||||||
"version": "8.1.0",
|
"version": "7.2.0",
|
||||||
"description": "Type check values",
|
"description": "Type check values",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "sindresorhus/is",
|
"repository": "sindresorhus/is",
|
||||||
|
|
@ -17,11 +17,11 @@
|
||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "del distribution && tsc",
|
"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"
|
"prepare": "npm run build"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|
@ -51,26 +51,31 @@
|
||||||
"typeguards",
|
"typeguards",
|
||||||
"types"
|
"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": {
|
"devDependencies": {
|
||||||
"@sindresorhus/tsconfig": "^8.1.0",
|
"@sindresorhus/tsconfig": "^6.0.0",
|
||||||
"@types/jsdom": "^28.0.1",
|
"@types/jsdom": "^21.1.7",
|
||||||
"@types/node": "^25.5.2",
|
"@types/node": "^20.14.10",
|
||||||
"@types/zen-observable": "^0.8.7",
|
"@types/zen-observable": "^0.8.7",
|
||||||
"del-cli": "^7.0.0",
|
"ava": "^6.1.3",
|
||||||
"expect-type": "^1.3.0",
|
"del-cli": "^5.1.0",
|
||||||
"jsdom": "^29.0.2",
|
"expect-type": "^0.19.0",
|
||||||
"rxjs": "^7.8.2",
|
"jsdom": "^24.1.0",
|
||||||
"tempy": "^3.2.0",
|
"rxjs": "^7.8.1",
|
||||||
"typescript": "6.0.2",
|
"tempy": "^3.1.0",
|
||||||
"xo": "^2.0.2",
|
"tsimp": "2.0.11",
|
||||||
|
"typescript": "5.5.3",
|
||||||
|
"xo": "^0.58.0",
|
||||||
"zen-observable": "^0.10.0"
|
"zen-observable": "^0.10.0"
|
||||||
|
},
|
||||||
|
"ava": {
|
||||||
|
"environmentVariables": {
|
||||||
|
"TSIMP_DIAG": "error"
|
||||||
|
},
|
||||||
|
"extensions": {
|
||||||
|
"ts": "module"
|
||||||
|
},
|
||||||
|
"nodeArguments": [
|
||||||
|
"--import=tsimp/import"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
80
readme.md
80
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.
|
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)
|
##### .function(value)
|
||||||
|
|
||||||
##### .buffer(value)
|
##### .buffer(value)
|
||||||
|
|
@ -474,10 +463,6 @@ function foo() {
|
||||||
foo();
|
foo();
|
||||||
```
|
```
|
||||||
|
|
||||||
##### .finiteNumber(value)
|
|
||||||
|
|
||||||
Check if `value` is a number and is finite. Excludes `Infinity` and `-Infinity`.
|
|
||||||
|
|
||||||
##### .positiveNumber(value)
|
##### .positiveNumber(value)
|
||||||
|
|
||||||
Check if `value` is a number and is more than 0.
|
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.
|
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)
|
##### .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.
|
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.
|
||||||
|
|
@ -680,17 +649,6 @@ is.optional(123, is.string);
|
||||||
//=> false
|
//=> 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)
|
##### .validDate(value)
|
||||||
|
|
||||||
Returns `true` if the value is a valid date.
|
Returns `true` if the value is a valid date.
|
||||||
|
|
@ -786,44 +744,6 @@ handleMovieRatingApiResponse({rating: 0.87, title: 'The Matrix'});
|
||||||
handleMovieRatingApiResponse({rating: '🦄'});
|
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
|
### Optional assertion
|
||||||
|
|
||||||
Asserts that `value` is `undefined` or satisfies the provided `assertion`.
|
Asserts that `value` is `undefined` or satisfies the provided `assertion`.
|
||||||
|
|
|
||||||
378
source/index.ts
378
source/index.ts
|
|
@ -1,33 +1,18 @@
|
||||||
import type {
|
import type {
|
||||||
ArrayLike,
|
ArrayLike,
|
||||||
Class,
|
Class,
|
||||||
EvenInteger,
|
|
||||||
Falsy,
|
Falsy,
|
||||||
FiniteNumber,
|
|
||||||
Integer,
|
|
||||||
NaN as NaNType,
|
|
||||||
NegativeInfinity,
|
|
||||||
NegativeInteger,
|
|
||||||
NegativeNumber,
|
|
||||||
NodeStream,
|
NodeStream,
|
||||||
NonEmptyString,
|
NonEmptyString,
|
||||||
NonNegativeInteger,
|
|
||||||
NonNegativeNumber,
|
|
||||||
ObservableLike,
|
ObservableLike,
|
||||||
OddInteger,
|
|
||||||
Predicate,
|
Predicate,
|
||||||
Primitive,
|
Primitive,
|
||||||
PositiveInfinity,
|
|
||||||
PositiveInteger,
|
|
||||||
PositiveNumber,
|
|
||||||
SafeInteger,
|
|
||||||
TypedArray,
|
TypedArray,
|
||||||
UrlString,
|
UrlString,
|
||||||
ValidLength,
|
|
||||||
WeakRef,
|
WeakRef,
|
||||||
Whitespace,
|
Whitespace,
|
||||||
} from './types.ts';
|
} from './types.js';
|
||||||
import {keysOf} from './utilities.ts';
|
import {keysOf} from './utilities.js';
|
||||||
|
|
||||||
// From type-fest.
|
// From type-fest.
|
||||||
type ExtractFromGlobalConstructors<Name extends string> =
|
type ExtractFromGlobalConstructors<Name extends string> =
|
||||||
|
|
@ -37,15 +22,6 @@ type ExtractFromGlobalConstructors<Name extends string> =
|
||||||
|
|
||||||
type NodeBuffer = ExtractFromGlobalConstructors<'Buffer'>;
|
type NodeBuffer = ExtractFromGlobalConstructors<'Buffer'>;
|
||||||
|
|
||||||
type NumericGuardResult<Input, Branded extends number> =
|
|
||||||
(
|
|
||||||
unknown extends Input
|
|
||||||
? Branded
|
|
||||||
: Input extends number
|
|
||||||
? Branded & Input
|
|
||||||
: number
|
|
||||||
) & Input;
|
|
||||||
|
|
||||||
const typedArrayTypeNames = [
|
const typedArrayTypeNames = [
|
||||||
'Int8Array',
|
'Int8Array',
|
||||||
'Uint8Array',
|
'Uint8Array',
|
||||||
|
|
@ -123,7 +99,6 @@ function isPrimitiveTypeName(name: unknown): name is PrimitiveTypeName {
|
||||||
export type TypeName = ObjectTypeName | PrimitiveTypeName;
|
export type TypeName = ObjectTypeName | PrimitiveTypeName;
|
||||||
|
|
||||||
const assertionTypeDescriptions = [
|
const assertionTypeDescriptions = [
|
||||||
'bound Function',
|
|
||||||
'positive number',
|
'positive number',
|
||||||
'negative number',
|
'negative number',
|
||||||
'Class',
|
'Class',
|
||||||
|
|
@ -158,13 +133,7 @@ const assertionTypeDescriptions = [
|
||||||
'non-empty map',
|
'non-empty map',
|
||||||
'PropertyKey',
|
'PropertyKey',
|
||||||
'even integer',
|
'even integer',
|
||||||
'finite number',
|
|
||||||
'negative integer',
|
|
||||||
'non-negative integer',
|
|
||||||
'non-negative number',
|
|
||||||
'odd integer',
|
'odd integer',
|
||||||
'positive integer',
|
|
||||||
'safe integer',
|
|
||||||
'T',
|
'T',
|
||||||
'in range',
|
'in range',
|
||||||
'predicate returns truthy for any value',
|
'predicate returns truthy for any value',
|
||||||
|
|
@ -181,7 +150,7 @@ export type AssertionTypeDescription = typeof assertionTypeDescriptions[number];
|
||||||
const getObjectType = (value: unknown): ObjectTypeName | undefined => {
|
const getObjectType = (value: unknown): ObjectTypeName | undefined => {
|
||||||
const objectTypeName = Object.prototype.toString.call(value).slice(8, -1);
|
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';
|
return 'HTMLElement';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,7 +166,6 @@ function detect(value: unknown): TypeName {
|
||||||
return 'null';
|
return 'null';
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case 'undefined': {
|
case 'undefined': {
|
||||||
return 'undefined';
|
return 'undefined';
|
||||||
|
|
@ -243,7 +211,7 @@ function detect(value: unknown): TypeName {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagType = getObjectType(value);
|
const tagType = getObjectType(value);
|
||||||
if (tagType !== undefined && tagType !== 'Object') {
|
if (tagType && tagType !== 'Object') {
|
||||||
return tagType;
|
return tagType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,7 +219,7 @@ function detect(value: unknown): TypeName {
|
||||||
return 'Promise';
|
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');
|
throw new TypeError('Please don\'t use object wrappers for primitive types');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,23 +230,6 @@ function hasPromiseApi<T = unknown>(value: unknown): value is Promise<T> {
|
||||||
return isFunction((value as Promise<T>)?.then) && isFunction((value as Promise<T>)?.catch);
|
return isFunction((value as Promise<T>)?.then) && isFunction((value as Promise<T>)?.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(
|
const is = Object.assign(
|
||||||
detect,
|
detect,
|
||||||
{
|
{
|
||||||
|
|
@ -287,7 +238,6 @@ const is = Object.assign(
|
||||||
array: isArray,
|
array: isArray,
|
||||||
arrayBuffer: isArrayBuffer,
|
arrayBuffer: isArrayBuffer,
|
||||||
arrayLike: isArrayLike,
|
arrayLike: isArrayLike,
|
||||||
arrayOf: isArrayOf,
|
|
||||||
asyncFunction: isAsyncFunction,
|
asyncFunction: isAsyncFunction,
|
||||||
asyncGenerator: isAsyncGenerator,
|
asyncGenerator: isAsyncGenerator,
|
||||||
asyncGeneratorFunction: isAsyncGeneratorFunction,
|
asyncGeneratorFunction: isAsyncGeneratorFunction,
|
||||||
|
|
@ -314,7 +264,6 @@ const is = Object.assign(
|
||||||
error: isError,
|
error: isError,
|
||||||
evenInteger: isEvenInteger,
|
evenInteger: isEvenInteger,
|
||||||
falsy: isFalsy,
|
falsy: isFalsy,
|
||||||
finiteNumber: isFiniteNumber,
|
|
||||||
float32Array: isFloat32Array,
|
float32Array: isFloat32Array,
|
||||||
float64Array: isFloat64Array,
|
float64Array: isFloat64Array,
|
||||||
formData: isFormData,
|
formData: isFormData,
|
||||||
|
|
@ -332,7 +281,6 @@ const is = Object.assign(
|
||||||
map: isMap,
|
map: isMap,
|
||||||
nan: isNan,
|
nan: isNan,
|
||||||
nativePromise: isNativePromise,
|
nativePromise: isNativePromise,
|
||||||
negativeInteger: isNegativeInteger,
|
|
||||||
negativeNumber: isNegativeNumber,
|
negativeNumber: isNegativeNumber,
|
||||||
nodeStream: isNodeStream,
|
nodeStream: isNodeStream,
|
||||||
nonEmptyArray: isNonEmptyArray,
|
nonEmptyArray: isNonEmptyArray,
|
||||||
|
|
@ -341,8 +289,6 @@ const is = Object.assign(
|
||||||
nonEmptySet: isNonEmptySet,
|
nonEmptySet: isNonEmptySet,
|
||||||
nonEmptyString: isNonEmptyString,
|
nonEmptyString: isNonEmptyString,
|
||||||
nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace,
|
nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace,
|
||||||
nonNegativeInteger: isNonNegativeInteger,
|
|
||||||
nonNegativeNumber: isNonNegativeNumber,
|
|
||||||
null: isNull,
|
null: isNull,
|
||||||
nullOrUndefined: isNullOrUndefined,
|
nullOrUndefined: isNullOrUndefined,
|
||||||
number: isNumber,
|
number: isNumber,
|
||||||
|
|
@ -350,9 +296,7 @@ const is = Object.assign(
|
||||||
object: isObject,
|
object: isObject,
|
||||||
observable: isObservable,
|
observable: isObservable,
|
||||||
oddInteger: isOddInteger,
|
oddInteger: isOddInteger,
|
||||||
oneOf: isOneOf,
|
|
||||||
plainObject: isPlainObject,
|
plainObject: isPlainObject,
|
||||||
positiveInteger: isPositiveInteger,
|
|
||||||
positiveNumber: isPositiveNumber,
|
positiveNumber: isPositiveNumber,
|
||||||
primitive: isPrimitive,
|
primitive: isPrimitive,
|
||||||
promise: isPromise,
|
promise: isPromise,
|
||||||
|
|
@ -403,13 +347,9 @@ function validatePredicateArray(predicateArray: readonly Predicate[], allowEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const predicate of predicateArray) {
|
for (const predicate of predicateArray) {
|
||||||
validatePredicate(predicate);
|
if (!isFunction(predicate)) {
|
||||||
}
|
throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validatePredicate(predicate: Predicate) {
|
|
||||||
if (!isFunction(predicate)) {
|
|
||||||
throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,10 +430,6 @@ export function isArrayLike<T = unknown>(value: unknown): value is ArrayLike<T>
|
||||||
return !isNullOrUndefined(value) && !isFunction(value) && isValidLength((value as ArrayLike<T>).length);
|
return !isNullOrUndefined(value) && !isFunction(value) && isValidLength((value as ArrayLike<T>).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isArrayOf<T>(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<T = unknown>(value: unknown): value is ((...arguments_: any[]) => Promise<T>) {
|
export function isAsyncFunction<T = unknown>(value: unknown): value is ((...arguments_: any[]) => Promise<T>) {
|
||||||
return getObjectType(value) === 'AsyncFunction';
|
return getObjectType(value) === 'AsyncFunction';
|
||||||
}
|
}
|
||||||
|
|
@ -530,7 +466,7 @@ export function isBoolean(value: unknown): value is boolean {
|
||||||
return value === true || value === false;
|
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 {
|
export function isBoundFunction(value: unknown): value is Function {
|
||||||
return isFunction(value) && !Object.hasOwn(value, 'prototype');
|
return isFunction(value) && !Object.hasOwn(value, 'prototype');
|
||||||
}
|
}
|
||||||
|
|
@ -539,12 +475,12 @@ export function isBoundFunction(value: unknown): value is Function {
|
||||||
Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer)
|
Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer)
|
||||||
*/
|
*/
|
||||||
export function isBuffer(value: unknown): value is NodeBuffer {
|
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;
|
return (value as any)?.constructor?.isBuffer?.(value) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isClass<T = unknown>(value: unknown): value is Class<T> {
|
export function isClass<T = unknown>(value: unknown): value is Class<T> {
|
||||||
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 {
|
export function isDataView(value: unknown): value is DataView {
|
||||||
|
|
@ -572,7 +508,7 @@ export function isEmptyMap(value: unknown): value is Map<never, never> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEmptyObject<Key extends keyof any = string>(value: unknown): value is Record<Key, never> {
|
export function isEmptyObject<Key extends keyof any = string>(value: unknown): value is Record<Key, never> {
|
||||||
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<never> {
|
export function isEmptySet(value: unknown): value is Set<never> {
|
||||||
|
|
@ -588,31 +524,16 @@ export function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitesp
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEnumCase<T = unknown>(value: unknown, targetEnum: T): value is T[keyof T] {
|
export function isEnumCase<T = unknown>(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.
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
const enumObject = targetEnum as Record<PropertyKey, unknown>;
|
return Object.values(targetEnum as any).includes(value as string);
|
||||||
|
|
||||||
return Object.entries(enumObject).some(([key, enumValue]) => {
|
|
||||||
if (!isString(enumValue)) {
|
|
||||||
return enumValue === value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const numericKey = Number(key);
|
|
||||||
if (Number.isNaN(numericKey) || String(numericKey) !== key) {
|
|
||||||
return enumValue === value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return enumValue === value && !(Object.hasOwn(enumObject, enumValue) && enumObject[enumValue] === numericKey);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isError(value: unknown): value is Error {
|
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';
|
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: unknown): value is number {
|
||||||
export function isEvenInteger<Input>(value: Input): value is NumericGuardResult<Input, EvenInteger>;
|
|
||||||
export function isEvenInteger(value: unknown): boolean {
|
|
||||||
return isAbsoluteModule2(0)(value);
|
return isAbsoluteModule2(0)(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -621,11 +542,6 @@ export function isFalsy(value: unknown): value is Falsy {
|
||||||
return !value;
|
return !value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFiniteNumber<Input>(value: Input): value is NumericGuardResult<Input, FiniteNumber>;
|
|
||||||
export function isFiniteNumber(value: unknown): boolean {
|
|
||||||
return Number.isFinite(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Support detecting Float16Array when targeting Node.js 24.
|
// TODO: Support detecting Float16Array when targeting Node.js 24.
|
||||||
|
|
||||||
export function isFloat32Array(value: unknown): value is Float32Array {
|
export function isFloat32Array(value: unknown): value is Float32Array {
|
||||||
|
|
@ -640,7 +556,7 @@ export function isFormData(value: unknown): value is FormData {
|
||||||
return getObjectType(value) === '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 {
|
export function isFunction(value: unknown): value is Function {
|
||||||
return typeof value === 'function';
|
return typeof value === 'function';
|
||||||
}
|
}
|
||||||
|
|
@ -653,9 +569,11 @@ export function isGeneratorFunction(value: unknown): value is GeneratorFunction
|
||||||
return getObjectType(value) === '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',
|
'innerHTML',
|
||||||
'ownerDocument',
|
'ownerDocument',
|
||||||
'style',
|
'style',
|
||||||
|
|
@ -671,8 +589,7 @@ export function isHtmlElement(value: unknown): value is HTMLElement {
|
||||||
&& DOM_PROPERTIES_TO_CHECK.every(property => property in value);
|
&& DOM_PROPERTIES_TO_CHECK.every(property => property in value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInfinite<Input>(value: Input): value is NumericGuardResult<Input, PositiveInfinity | NegativeInfinity>;
|
export function isInfinite(value: unknown): value is number {
|
||||||
export function isInfinite(value: unknown): boolean {
|
|
||||||
return value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY;
|
return value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,10 +599,6 @@ export function isInRange(value: number, range: number | [number, number]): valu
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isArray(range) && range.length === 2) {
|
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);
|
return value >= Math.min(...range) && value <= Math.max(...range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -704,8 +617,7 @@ export function isInt8Array(value: unknown): value is Int8Array {
|
||||||
return getObjectType(value) === 'Int8Array';
|
return getObjectType(value) === 'Int8Array';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInteger<Input>(value: Input): value is NumericGuardResult<Input, Integer>;
|
export function isInteger(value: unknown): value is number {
|
||||||
export function isInteger(value: unknown): boolean {
|
|
||||||
return Number.isInteger(value);
|
return Number.isInteger(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -717,8 +629,7 @@ export function isMap<Key = unknown, Value = unknown>(value: unknown): value is
|
||||||
return getObjectType(value) === 'Map';
|
return getObjectType(value) === 'Map';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNan<Input>(value: Input): value is NumericGuardResult<Input, NaNType>;
|
export function isNan(value: unknown) {
|
||||||
export function isNan(value: unknown): boolean {
|
|
||||||
return Number.isNaN(value);
|
return Number.isNaN(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -726,13 +637,7 @@ export function isNativePromise<T = unknown>(value: unknown): value is Promise<T
|
||||||
return getObjectType(value) === 'Promise';
|
return getObjectType(value) === 'Promise';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNegativeInteger<Input>(value: Input): value is NumericGuardResult<Input, NegativeInteger>;
|
export function isNegativeNumber(value: unknown): value is number {
|
||||||
export function isNegativeInteger(value: unknown): boolean {
|
|
||||||
return isInteger(value) && value < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isNegativeNumber<Input>(value: Input): value is NumericGuardResult<Input, NegativeNumber>;
|
|
||||||
export function isNegativeNumber(value: unknown): boolean {
|
|
||||||
return isNumber(value) && value < 0;
|
return isNumber(value) && value < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -751,7 +656,7 @@ export function isNonEmptyMap<Key = unknown, Value = unknown>(value: unknown): v
|
||||||
// TODO: Use `not` operator here to remove `Map` and `Set` from type guard:
|
// TODO: Use `not` operator here to remove `Map` and `Set` from type guard:
|
||||||
// - https://github.com/Microsoft/TypeScript/pull/29317
|
// - https://github.com/Microsoft/TypeScript/pull/29317
|
||||||
export function isNonEmptyObject<Key extends keyof any = string, Value = unknown>(value: unknown): value is Record<Key, Value> {
|
export function isNonEmptyObject<Key extends keyof any = string, Value = unknown>(value: unknown): value is Record<Key, Value> {
|
||||||
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<T = unknown>(value: unknown): value is Set<T> {
|
export function isNonEmptySet<T = unknown>(value: unknown): value is Set<T> {
|
||||||
|
|
@ -768,22 +673,12 @@ export function isNonEmptyStringAndNotWhitespace(value: unknown): value is NonEm
|
||||||
return isString(value) && !isEmptyStringOrWhitespace(value);
|
return isString(value) && !isEmptyStringOrWhitespace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNonNegativeInteger<Input>(value: Input): value is NumericGuardResult<Input, NonNegativeInteger>;
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
export function isNonNegativeInteger(value: unknown): boolean {
|
|
||||||
return isInteger(value) && value >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isNonNegativeNumber<Input>(value: Input): value is NumericGuardResult<Input, NonNegativeNumber>;
|
|
||||||
export function isNonNegativeNumber(value: unknown): boolean {
|
|
||||||
return isNumber(value) && value >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
export function isNull(value: unknown): value is null {
|
export function isNull(value: unknown): value is null {
|
||||||
return value === 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 {
|
export function isNullOrUndefined(value: unknown): value is null | undefined {
|
||||||
return isNull(value) || isUndefined(value);
|
return isNull(value) || isUndefined(value);
|
||||||
}
|
}
|
||||||
|
|
@ -793,10 +688,10 @@ export function isNumber(value: unknown): value is number {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNumericString(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 {
|
export function isObject(value: unknown): value is object {
|
||||||
return !isNull(value) && (typeof value === 'object' || isFunction(value));
|
return !isNull(value) && (typeof value === 'object' || isFunction(value));
|
||||||
}
|
}
|
||||||
|
|
@ -806,12 +701,12 @@ export function isObservable(value: unknown): value is ObservableLike {
|
||||||
return false;
|
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]?.()) {
|
if (Symbol.observable !== undefined && value === (value as any)[Symbol.observable]?.()) {
|
||||||
return true;
|
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']?.()) {
|
if (value === (value as any)['@@observable']?.()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -819,15 +714,10 @@ export function isObservable(value: unknown): value is ObservableLike {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOddInteger<Input>(value: Input): value is NumericGuardResult<Input, OddInteger>;
|
export function isOddInteger(value: unknown): value is number {
|
||||||
export function isOddInteger(value: unknown): boolean {
|
|
||||||
return isAbsoluteModule2(1)(value);
|
return isAbsoluteModule2(1)(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOneOf<T extends readonly unknown[]>(values: T): (value: unknown) => value is T[number] {
|
|
||||||
return (value: unknown): value is T[number] => values.includes(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPlainObject<Value = unknown>(value: unknown): value is Record<PropertyKey, Value> {
|
export function isPlainObject<Value = unknown>(value: unknown): value is Record<PropertyKey, Value> {
|
||||||
// From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
|
// From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
|
||||||
if (typeof value !== 'object' || value === null) {
|
if (typeof value !== 'object' || value === null) {
|
||||||
|
|
@ -840,13 +730,7 @@ export function isPlainObject<Value = unknown>(value: unknown): value is Record<
|
||||||
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
|
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPositiveInteger<Input>(value: Input): value is NumericGuardResult<Input, PositiveInteger>;
|
export function isPositiveNumber(value: unknown): value is number {
|
||||||
export function isPositiveInteger(value: unknown): boolean {
|
|
||||||
return isInteger(value) && value > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPositiveNumber<Input>(value: Input): value is NumericGuardResult<Input, PositiveNumber>;
|
|
||||||
export function isPositiveNumber(value: unknown): boolean {
|
|
||||||
return isNumber(value) && value > 0;
|
return isNumber(value) && value > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -858,7 +742,7 @@ export function isPromise<T = unknown>(value: unknown): value is Promise<T> {
|
||||||
return isNativePromise(value) || hasPromiseApi(value);
|
return isNativePromise(value) || hasPromiseApi(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// `PropertyKey` is any value that can be used as an object key (string, number, or symbol). Note: NaN is technically `typeof 'number'` and thus fits TypeScript's `PropertyKey`, but we intentionally exclude it here because using NaN as a property key is almost always a mistake.
|
// `PropertyKey` is any value that can be used as an object key (string, number, or symbol)
|
||||||
export function isPropertyKey(value: unknown): value is PropertyKey {
|
export function isPropertyKey(value: unknown): value is PropertyKey {
|
||||||
return isAny([isString, isNumber, isSymbol], value);
|
return isAny([isString, isNumber, isSymbol], value);
|
||||||
}
|
}
|
||||||
|
|
@ -867,8 +751,7 @@ export function isRegExp(value: unknown): value is RegExp {
|
||||||
return getObjectType(value) === 'RegExp';
|
return getObjectType(value) === 'RegExp';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSafeInteger<Input>(value: Input): value is NumericGuardResult<Input, SafeInteger>;
|
export function isSafeInteger(value: unknown): value is number {
|
||||||
export function isSafeInteger(value: unknown): boolean {
|
|
||||||
return Number.isSafeInteger(value);
|
return Number.isSafeInteger(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -894,8 +777,8 @@ export function isTruthy<T>(value: T | Falsy): value is T {
|
||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
type ResolveTypesOfTypeGuardsTuple<TypeGuardsOfT, ResultOfT extends unknown[] = []> =
|
type ResolveTypesOfTypeGuardsTuple<TypeGuardsOfT, ResultOfT extends unknown[] = [] > =
|
||||||
TypeGuardsOfT extends [TypeGuard<infer U>, ...infer TOthers]
|
TypeGuardsOfT extends [TypeGuard<infer U>, ...infer TOthers]
|
||||||
? ResolveTypesOfTypeGuardsTuple<TOthers, [...ResultOfT, U]>
|
? ResolveTypesOfTypeGuardsTuple<TOthers, [...ResultOfT, U]>
|
||||||
: TypeGuardsOfT extends undefined[]
|
: TypeGuardsOfT extends undefined[]
|
||||||
|
|
@ -960,34 +843,35 @@ export function isValidDate(value: unknown): value is Date {
|
||||||
return isDate(value) && !isNan(Number(value));
|
return isDate(value) && !isNan(Number(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidLength<Input>(value: Input): value is NumericGuardResult<Input, ValidLength>;
|
export function isValidLength(value: unknown): value is number {
|
||||||
export function isValidLength(value: unknown): boolean {
|
|
||||||
return isSafeInteger(value) && value >= 0;
|
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<Key extends object = object, Value = unknown>(value: unknown): value is WeakMap<Key, Value> {
|
export function isWeakMap<Key extends object = object, Value = unknown>(value: unknown): value is WeakMap<Key, Value> {
|
||||||
return getObjectType(value) === '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<object> {
|
export function isWeakRef(value: unknown): value is WeakRef<object> {
|
||||||
return getObjectType(value) === '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<object> {
|
export function isWeakSet(value: unknown): value is WeakSet<object> {
|
||||||
return getObjectType(value) === 'WeakSet';
|
return getObjectType(value) === 'WeakSet';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isWhitespaceString(value: unknown): value is Whitespace {
|
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;
|
type ArrayMethod = (function_: (value: unknown, index: number, array: unknown[]) => boolean, thisArgument?: unknown) => boolean;
|
||||||
|
|
||||||
function predicateOnArray(method: ArrayMethod, predicate: Predicate, values: unknown[]) {
|
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) {
|
if (values.length === 0) {
|
||||||
throw new TypeError('Invalid number of values');
|
throw new TypeError('Invalid number of values');
|
||||||
|
|
@ -1000,17 +884,6 @@ function typeErrorMessage(description: AssertionTypeDescription, value: unknown)
|
||||||
return `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`;
|
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<Value, Forbidden, UnknownResult> = Exclude<Value, Forbidden> & ([unknown] extends [Value] ? UnknownResult : unknown);
|
|
||||||
|
|
||||||
type NotAssertion<Forbidden, UnknownResult = unknown> = <Value>(value: Value, message?: string) => asserts value is NotAssertionResult<Value, Forbidden, UnknownResult>;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
type UnknownNotPrimitive<Forbidden extends Primitive> = Exclude<Primitive, Forbidden> | object;
|
|
||||||
|
|
||||||
function unique<T>(values: T[]): T[] {
|
function unique<T>(values: T[]): T[] {
|
||||||
// eslint-disable-next-line unicorn/prefer-spread
|
// eslint-disable-next-line unicorn/prefer-spread
|
||||||
return Array.from(new Set(values));
|
return Array.from(new Set(values));
|
||||||
|
|
@ -1026,24 +899,17 @@ function typeErrorMessageMultipleValues(expectedType: AssertionTypeDescription |
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type assertions have to be declared with an explicit type.
|
// 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 = {
|
type Assert = {
|
||||||
// Unknowns.
|
// Unknowns.
|
||||||
undefined: (value: unknown, message?: string) => asserts value is undefined;
|
undefined: (value: unknown, message?: string) => asserts value is undefined;
|
||||||
string: (value: unknown, message?: string) => asserts value is string;
|
string: (value: unknown, message?: string) => asserts value is string;
|
||||||
number: (value: unknown, message?: string) => asserts value is number;
|
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;
|
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;
|
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;
|
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;
|
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;
|
null: (value: unknown, message?: string) => asserts value is null;
|
||||||
class: <T = unknown>(value: unknown, message?: string) => asserts value is Class<T>;
|
class: <T = unknown>(value: unknown, message?: string) => asserts value is Class<T>;
|
||||||
boolean: (value: unknown, message?: string) => asserts value is boolean;
|
boolean: (value: unknown, message?: string) => asserts value is boolean;
|
||||||
|
|
@ -1052,7 +918,7 @@ type Assert = {
|
||||||
array: <T = unknown>(value: unknown, assertion?: (element: unknown) => asserts element is T, message?: string) => asserts value is T[];
|
array: <T = unknown>(value: unknown, assertion?: (element: unknown) => asserts element is T, message?: string) => asserts value is T[];
|
||||||
buffer: (value: unknown, message?: string) => asserts value is NodeBuffer;
|
buffer: (value: unknown, message?: string) => asserts value is NodeBuffer;
|
||||||
blob: (value: unknown, message?: string) => asserts value is Blob;
|
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;
|
nullOrUndefined: (value: unknown, message?: string) => asserts value is null | undefined;
|
||||||
object: <Key extends keyof any = string, Value = unknown>(value: unknown, message?: string) => asserts value is Record<Key, Value>;
|
object: <Key extends keyof any = string, Value = unknown>(value: unknown, message?: string) => asserts value is Record<Key, Value>;
|
||||||
iterable: <T = unknown>(value: unknown, message?: string) => asserts value is Iterable<T>;
|
iterable: <T = unknown>(value: unknown, message?: string) => asserts value is Iterable<T>;
|
||||||
|
|
@ -1063,20 +929,20 @@ type Assert = {
|
||||||
promise: <T = unknown>(value: unknown, message?: string) => asserts value is Promise<T>;
|
promise: <T = unknown>(value: unknown, message?: string) => asserts value is Promise<T>;
|
||||||
generatorFunction: (value: unknown, message?: string) => asserts value is GeneratorFunction;
|
generatorFunction: (value: unknown, message?: string) => asserts value is GeneratorFunction;
|
||||||
asyncGeneratorFunction: (value: unknown, message?: string) => asserts value is AsyncGeneratorFunction;
|
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;
|
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;
|
boundFunction: (value: unknown, message?: string) => asserts value is Function;
|
||||||
regExp: (value: unknown, message?: string) => asserts value is RegExp;
|
regExp: (value: unknown, message?: string) => asserts value is RegExp;
|
||||||
date: (value: unknown, message?: string) => asserts value is Date;
|
date: (value: unknown, message?: string) => asserts value is Date;
|
||||||
error: (value: unknown, message?: string) => asserts value is Error;
|
error: (value: unknown, message?: string) => asserts value is Error;
|
||||||
map: <Key = unknown, Value = unknown>(value: unknown, message?: string) => asserts value is Map<Key, Value>;
|
map: <Key = unknown, Value = unknown>(value: unknown, message?: string) => asserts value is Map<Key, Value>;
|
||||||
set: <T = unknown>(value: unknown, message?: string) => asserts value is Set<T>;
|
set: <T = unknown>(value: unknown, message?: string) => asserts value is Set<T>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
weakMap: <Key extends object = object, Value = unknown>(value: unknown, message?: string) => asserts value is WeakMap<Key, Value>;
|
weakMap: <Key extends object = object, Value = unknown>(value: unknown, message?: string) => asserts value is WeakMap<Key, Value>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
weakSet: <T extends object = object>(value: unknown, message?: string) => asserts value is WeakSet<T>;
|
weakSet: <T extends object = object>(value: unknown, message?: string) => asserts value is WeakSet<T>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
weakRef: <T extends object = object>(value: unknown, message?: string) => asserts value is WeakRef<T>;
|
weakRef: <T extends object = object>(value: unknown, message?: string) => asserts value is WeakRef<T>;
|
||||||
int8Array: (value: unknown, message?: string) => asserts value is Int8Array;
|
int8Array: (value: unknown, message?: string) => asserts value is Int8Array;
|
||||||
uint8Array: (value: unknown, message?: string) => asserts value is Uint8Array;
|
uint8Array: (value: unknown, message?: string) => asserts value is Uint8Array;
|
||||||
|
|
@ -1136,8 +1002,6 @@ type Assert = {
|
||||||
directInstanceOf: <T>(instance: unknown, class_: Class<T>, message?: string) => asserts instance is T;
|
directInstanceOf: <T>(instance: unknown, class_: Class<T>, message?: string) => asserts instance is T;
|
||||||
inRange: (value: number, range: number | [number, number], message?: string) => asserts value is number;
|
inRange: (value: number, range: number | [number, number], message?: string) => asserts value is number;
|
||||||
|
|
||||||
not: NotAssert;
|
|
||||||
|
|
||||||
// Variadic functions.
|
// Variadic functions.
|
||||||
any: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never;
|
any: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never;
|
||||||
all: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never;
|
all: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never;
|
||||||
|
|
@ -1150,58 +1014,9 @@ type Assert = {
|
||||||
optional: <T>(value: unknown, assertion: (value: unknown, message?: string) => asserts value is T, message?: string) => asserts value is T | undefined;
|
optional: <T>(value: unknown, assertion: (value: unknown, message?: string) => asserts value is T, message?: string) => asserts value is T | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NotAssert = {
|
|
||||||
undefined: NotAssertion<undefined, UnknownNotPrimitive<undefined>>;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
null: NotAssertion<null, UnknownNotPrimitive<null>>;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
nullOrUndefined: NotAssertion<null | undefined, UnknownNotPrimitive<null | undefined>>;
|
|
||||||
string: NotAssertion<string, UnknownNotPrimitive<string>>;
|
|
||||||
boolean: NotAssertion<boolean, UnknownNotPrimitive<boolean>>;
|
|
||||||
symbol: NotAssertion<symbol, UnknownNotPrimitive<symbol>>;
|
|
||||||
bigint: NotAssertion<bigint, UnknownNotPrimitive<bigint>>;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
primitive: NotAssertion<Primitive, object>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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<Forbidden, UnknownResult = unknown>(predicate: Predicate, description: AssertionTypeDescription): NotAssertion<Forbidden, UnknownResult> {
|
|
||||||
return <Value>(value: Value, message?: string): asserts value is NotAssertionResult<Value, Forbidden, UnknownResult> => {
|
|
||||||
if (predicate(value)) {
|
|
||||||
throw new TypeError(message ?? typeErrorMessageNot(description, value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const assertNotUndefined: NotAssertion<undefined, UnknownNotPrimitive<undefined>> = createAssertNot<undefined, UnknownNotPrimitive<undefined>>(isUndefined, 'undefined');
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
export const assertNotNull: NotAssertion<null, UnknownNotPrimitive<null>> = createAssertNot<null, UnknownNotPrimitive<null>>(isNull, 'null');
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
export const assertNotNullOrUndefined: NotAssertion<null | undefined, UnknownNotPrimitive<null | undefined>>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
= createAssertNot<null | undefined, UnknownNotPrimitive<null | undefined>>(isNullOrUndefined, 'null or undefined');
|
|
||||||
export const assertNotString: NotAssertion<string, UnknownNotPrimitive<string>> = createAssertNot<string, UnknownNotPrimitive<string>>(isString, 'string');
|
|
||||||
export const assertNotBoolean: NotAssertion<boolean, UnknownNotPrimitive<boolean>> = createAssertNot<boolean, UnknownNotPrimitive<boolean>>(isBoolean, 'boolean');
|
|
||||||
export const assertNotSymbol: NotAssertion<symbol, UnknownNotPrimitive<symbol>> = createAssertNot<symbol, UnknownNotPrimitive<symbol>>(isSymbol, 'symbol');
|
|
||||||
export const assertNotBigint: NotAssertion<bigint, UnknownNotPrimitive<bigint>> = createAssertNot<bigint, UnknownNotPrimitive<bigint>>(isBigint, 'bigint');
|
|
||||||
export const assertNotPrimitive: NotAssertion<Primitive, object> = createAssertNot<Primitive, object>(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 = {
|
export const assert: Assert = {
|
||||||
all: assertAll,
|
all: assertAll,
|
||||||
any: assertAny,
|
any: assertAny,
|
||||||
not: notAssertions,
|
|
||||||
optional: assertOptional,
|
optional: assertOptional,
|
||||||
array: assertArray,
|
array: assertArray,
|
||||||
arrayBuffer: assertArrayBuffer,
|
arrayBuffer: assertArrayBuffer,
|
||||||
|
|
@ -1231,7 +1046,6 @@ export const assert: Assert = {
|
||||||
error: assertError,
|
error: assertError,
|
||||||
evenInteger: assertEvenInteger,
|
evenInteger: assertEvenInteger,
|
||||||
falsy: assertFalsy,
|
falsy: assertFalsy,
|
||||||
finiteNumber: assertFiniteNumber,
|
|
||||||
float32Array: assertFloat32Array,
|
float32Array: assertFloat32Array,
|
||||||
float64Array: assertFloat64Array,
|
float64Array: assertFloat64Array,
|
||||||
formData: assertFormData,
|
formData: assertFormData,
|
||||||
|
|
@ -1249,7 +1063,6 @@ export const assert: Assert = {
|
||||||
map: assertMap,
|
map: assertMap,
|
||||||
nan: assertNan,
|
nan: assertNan,
|
||||||
nativePromise: assertNativePromise,
|
nativePromise: assertNativePromise,
|
||||||
negativeInteger: assertNegativeInteger,
|
|
||||||
negativeNumber: assertNegativeNumber,
|
negativeNumber: assertNegativeNumber,
|
||||||
nodeStream: assertNodeStream,
|
nodeStream: assertNodeStream,
|
||||||
nonEmptyArray: assertNonEmptyArray,
|
nonEmptyArray: assertNonEmptyArray,
|
||||||
|
|
@ -1258,8 +1071,6 @@ export const assert: Assert = {
|
||||||
nonEmptySet: assertNonEmptySet,
|
nonEmptySet: assertNonEmptySet,
|
||||||
nonEmptyString: assertNonEmptyString,
|
nonEmptyString: assertNonEmptyString,
|
||||||
nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace,
|
nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace,
|
||||||
nonNegativeInteger: assertNonNegativeInteger,
|
|
||||||
nonNegativeNumber: assertNonNegativeNumber,
|
|
||||||
null: assertNull,
|
null: assertNull,
|
||||||
nullOrUndefined: assertNullOrUndefined,
|
nullOrUndefined: assertNullOrUndefined,
|
||||||
number: assertNumber,
|
number: assertNumber,
|
||||||
|
|
@ -1268,7 +1079,6 @@ export const assert: Assert = {
|
||||||
observable: assertObservable,
|
observable: assertObservable,
|
||||||
oddInteger: assertOddInteger,
|
oddInteger: assertOddInteger,
|
||||||
plainObject: assertPlainObject,
|
plainObject: assertPlainObject,
|
||||||
positiveInteger: assertPositiveInteger,
|
|
||||||
positiveNumber: assertPositiveNumber,
|
positiveNumber: assertPositiveNumber,
|
||||||
primitive: assertPrimitive,
|
primitive: assertPrimitive,
|
||||||
promise: assertPromise,
|
promise: assertPromise,
|
||||||
|
|
@ -1311,7 +1121,7 @@ const methodTypeMap = {
|
||||||
isBigUint64Array: 'BigUint64Array',
|
isBigUint64Array: 'BigUint64Array',
|
||||||
isBlob: 'Blob',
|
isBlob: 'Blob',
|
||||||
isBoolean: 'boolean',
|
isBoolean: 'boolean',
|
||||||
isBoundFunction: 'bound Function',
|
isBoundFunction: 'Function',
|
||||||
isBuffer: 'Buffer',
|
isBuffer: 'Buffer',
|
||||||
isClass: 'Class',
|
isClass: 'Class',
|
||||||
isDataView: 'DataView',
|
isDataView: 'DataView',
|
||||||
|
|
@ -1327,7 +1137,6 @@ const methodTypeMap = {
|
||||||
isError: 'Error',
|
isError: 'Error',
|
||||||
isEvenInteger: 'even integer',
|
isEvenInteger: 'even integer',
|
||||||
isFalsy: 'falsy',
|
isFalsy: 'falsy',
|
||||||
isFiniteNumber: 'finite number',
|
|
||||||
isFloat32Array: 'Float32Array',
|
isFloat32Array: 'Float32Array',
|
||||||
isFloat64Array: 'Float64Array',
|
isFloat64Array: 'Float64Array',
|
||||||
isFormData: 'FormData',
|
isFormData: 'FormData',
|
||||||
|
|
@ -1345,7 +1154,6 @@ const methodTypeMap = {
|
||||||
isMap: 'Map',
|
isMap: 'Map',
|
||||||
isNan: 'NaN',
|
isNan: 'NaN',
|
||||||
isNativePromise: 'native Promise',
|
isNativePromise: 'native Promise',
|
||||||
isNegativeInteger: 'negative integer',
|
|
||||||
isNegativeNumber: 'negative number',
|
isNegativeNumber: 'negative number',
|
||||||
isNodeStream: 'Node.js Stream',
|
isNodeStream: 'Node.js Stream',
|
||||||
isNonEmptyArray: 'non-empty array',
|
isNonEmptyArray: 'non-empty array',
|
||||||
|
|
@ -1354,8 +1162,6 @@ const methodTypeMap = {
|
||||||
isNonEmptySet: 'non-empty set',
|
isNonEmptySet: 'non-empty set',
|
||||||
isNonEmptyString: 'non-empty string',
|
isNonEmptyString: 'non-empty string',
|
||||||
isNonEmptyStringAndNotWhitespace: 'non-empty string and not whitespace',
|
isNonEmptyStringAndNotWhitespace: 'non-empty string and not whitespace',
|
||||||
isNonNegativeInteger: 'non-negative integer',
|
|
||||||
isNonNegativeNumber: 'non-negative number',
|
|
||||||
isNull: 'null',
|
isNull: 'null',
|
||||||
isNullOrUndefined: 'null or undefined',
|
isNullOrUndefined: 'null or undefined',
|
||||||
isNumber: 'number',
|
isNumber: 'number',
|
||||||
|
|
@ -1364,13 +1170,12 @@ const methodTypeMap = {
|
||||||
isObservable: 'Observable',
|
isObservable: 'Observable',
|
||||||
isOddInteger: 'odd integer',
|
isOddInteger: 'odd integer',
|
||||||
isPlainObject: 'plain object',
|
isPlainObject: 'plain object',
|
||||||
isPositiveInteger: 'positive integer',
|
|
||||||
isPositiveNumber: 'positive number',
|
isPositiveNumber: 'positive number',
|
||||||
isPrimitive: 'primitive',
|
isPrimitive: 'primitive',
|
||||||
isPromise: 'Promise',
|
isPromise: 'Promise',
|
||||||
isPropertyKey: 'PropertyKey',
|
isPropertyKey: 'PropertyKey',
|
||||||
isRegExp: 'RegExp',
|
isRegExp: 'RegExp',
|
||||||
isSafeInteger: 'safe integer',
|
isSafeInteger: 'integer',
|
||||||
isSet: 'Set',
|
isSet: 'Set',
|
||||||
isSharedArrayBuffer: 'SharedArrayBuffer',
|
isSharedArrayBuffer: 'SharedArrayBuffer',
|
||||||
isString: 'string',
|
isString: 'string',
|
||||||
|
|
@ -1456,7 +1261,7 @@ export function assertArrayLike<T = unknown>(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 {
|
export function assertAsyncFunction(value: unknown, message?: string): asserts value is Function {
|
||||||
if (!isAsyncFunction(value)) {
|
if (!isAsyncFunction(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value));
|
throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value));
|
||||||
|
|
@ -1511,10 +1316,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 {
|
export function assertBoundFunction(value: unknown, message?: string): asserts value is Function {
|
||||||
if (!isBoundFunction(value)) {
|
if (!isBoundFunction(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('bound Function', value));
|
throw new TypeError(message ?? typeErrorMessage('Function', value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1611,12 +1416,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 {
|
export function assertFloat32Array(value: unknown, message?: string): asserts value is Float32Array {
|
||||||
if (!isFloat32Array(value)) {
|
if (!isFloat32Array(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('Float32Array', value));
|
throw new TypeError(message ?? typeErrorMessage('Float32Array', value));
|
||||||
|
|
@ -1635,7 +1434,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 {
|
export function assertFunction(value: unknown, message?: string): asserts value is Function {
|
||||||
if (!isFunction(value)) {
|
if (!isFunction(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('Function', value));
|
throw new TypeError(message ?? typeErrorMessage('Function', value));
|
||||||
|
|
@ -1720,12 +1519,6 @@ export function assertNativePromise<T = unknown>(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 {
|
export function assertNegativeNumber(value: unknown, message?: string): asserts value is number {
|
||||||
if (!isNegativeNumber(value)) {
|
if (!isNegativeNumber(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('negative number', value));
|
throw new TypeError(message ?? typeErrorMessage('negative number', value));
|
||||||
|
|
@ -1774,26 +1567,14 @@ export function assertNonEmptyStringAndNotWhitespace(value: unknown, message?: s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertNonNegativeInteger(value: unknown, message?: string): asserts value is number {
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
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
|
|
||||||
export function assertNull(value: unknown, message?: string): asserts value is null {
|
export function assertNull(value: unknown, message?: string): asserts value is null {
|
||||||
if (!isNull(value)) {
|
if (!isNull(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('null', 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 {
|
export function assertNullOrUndefined(value: unknown, message?: string): asserts value is null | undefined {
|
||||||
if (!isNullOrUndefined(value)) {
|
if (!isNullOrUndefined(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('null or undefined', value));
|
throw new TypeError(message ?? typeErrorMessage('null or undefined', value));
|
||||||
|
|
@ -1812,7 +1593,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 {
|
export function assertObject(value: unknown, message?: string): asserts value is object {
|
||||||
if (!isObject(value)) {
|
if (!isObject(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('Object', value));
|
throw new TypeError(message ?? typeErrorMessage('Object', value));
|
||||||
|
|
@ -1837,12 +1618,6 @@ export function assertPlainObject<Value = unknown>(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 {
|
export function assertPositiveNumber(value: unknown, message?: string): asserts value is number {
|
||||||
if (!isPositiveNumber(value)) {
|
if (!isPositiveNumber(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('positive number', value));
|
throw new TypeError(message ?? typeErrorMessage('positive number', value));
|
||||||
|
|
@ -1861,7 +1636,7 @@ export function assertPromise<T = unknown>(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)) {
|
if (!isPropertyKey(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('PropertyKey', value));
|
throw new TypeError(message ?? typeErrorMessage('PropertyKey', value));
|
||||||
}
|
}
|
||||||
|
|
@ -1875,7 +1650,7 @@ export function assertRegExp(value: unknown, message?: string): asserts value is
|
||||||
|
|
||||||
export function assertSafeInteger(value: unknown, message?: string): asserts value is number {
|
export function assertSafeInteger(value: unknown, message?: string): asserts value is number {
|
||||||
if (!isSafeInteger(value)) {
|
if (!isSafeInteger(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('safe integer', value));
|
throw new TypeError(message ?? typeErrorMessage('integer', value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1982,21 +1757,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<Key extends object = object, Value = unknown>(value: unknown, message?: string): asserts value is WeakMap<Key, Value> {
|
export function assertWeakMap<Key extends object = object, Value = unknown>(value: unknown, message?: string): asserts value is WeakMap<Key, Value> {
|
||||||
if (!isWeakMap(value)) {
|
if (!isWeakMap(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('WeakMap', 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<T extends object = object>(value: unknown, message?: string): asserts value is WeakRef<T> {
|
export function assertWeakRef<T extends object = object>(value: unknown, message?: string): asserts value is WeakRef<T> {
|
||||||
if (!isWeakRef(value)) {
|
if (!isWeakRef(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('WeakRef', 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<T extends object = object>(value: unknown, message?: string): asserts value is WeakSet<T> {
|
export function assertWeakSet<T extends object = object>(value: unknown, message?: string): asserts value is WeakSet<T> {
|
||||||
if (!isWeakSet(value)) {
|
if (!isWeakSet(value)) {
|
||||||
throw new TypeError(message ?? typeErrorMessage('WeakSet', value));
|
throw new TypeError(message ?? typeErrorMessage('WeakSet', value));
|
||||||
|
|
@ -2014,25 +1789,10 @@ export default is;
|
||||||
export type {
|
export type {
|
||||||
ArrayLike,
|
ArrayLike,
|
||||||
Class,
|
Class,
|
||||||
EvenInteger,
|
|
||||||
FiniteNumber,
|
|
||||||
Integer,
|
|
||||||
NaN,
|
|
||||||
NegativeInfinity,
|
|
||||||
NegativeInteger,
|
|
||||||
NegativeNumber,
|
|
||||||
NodeStream,
|
NodeStream,
|
||||||
NonNegativeInteger,
|
|
||||||
NonNegativeNumber,
|
|
||||||
ObservableLike,
|
ObservableLike,
|
||||||
OddInteger,
|
|
||||||
PositiveInfinity,
|
|
||||||
PositiveInteger,
|
|
||||||
PositiveNumber,
|
|
||||||
Predicate,
|
Predicate,
|
||||||
Primitive,
|
Primitive,
|
||||||
SafeInteger,
|
|
||||||
TypedArray,
|
TypedArray,
|
||||||
UrlString,
|
UrlString,
|
||||||
ValidLength,
|
} from './types.js';
|
||||||
} from './types.ts';
|
|
||||||
|
|
|
||||||
121
source/types.ts
121
source/types.ts
|
|
@ -4,8 +4,7 @@
|
||||||
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
||||||
*/
|
*/
|
||||||
export type Primitive =
|
export type Primitive =
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
| null // eslint-disable-line @typescript-eslint/ban-types
|
||||||
| null
|
|
||||||
| undefined
|
| undefined
|
||||||
| string
|
| string
|
||||||
| number
|
| number
|
||||||
|
|
@ -54,11 +53,10 @@ export type ObservableLike = {
|
||||||
[Symbol.observable](): 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;
|
export type Falsy = false | 0 | 0n | '' | null | undefined;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
export type WeakRef<T extends object> = { // eslint-disable-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations
|
||||||
export type WeakRef<T extends object> = {
|
|
||||||
readonly [Symbol.toStringTag]: 'WeakRef';
|
readonly [Symbol.toStringTag]: 'WeakRef';
|
||||||
deref(): T | undefined;
|
deref(): T | undefined;
|
||||||
};
|
};
|
||||||
|
|
@ -78,122 +76,9 @@ export type NonEmptyString = string & {0: string};
|
||||||
|
|
||||||
export type Whitespace = ' ';
|
export type Whitespace = ' ';
|
||||||
|
|
||||||
type Brand<Key extends string> = Readonly<Record<Key, true>>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A string that represents a valid URL.
|
A string that represents a valid URL.
|
||||||
|
|
||||||
This is a branded type to prevent incorrect TypeScript type narrowing.
|
This is a branded type to prevent incorrect TypeScript type narrowing.
|
||||||
*/
|
*/
|
||||||
export type UrlString = string & {readonly __brand: 'UrlString'};
|
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'>;
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export function keysOf<T extends Record<PropertyKey, unknown>>(value: T): Array<keyof T> {
|
export function keysOf<T extends Record<PropertyKey, unknown>>(value: T): Array<keyof T> {
|
||||||
return Object.keys(value) as Array<keyof T>; // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
|
return Object.keys(value) as Array<keyof T>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2427
test/test.ts
2427
test/test.ts
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"rootDir": "..",
|
|
||||||
"noUnusedLocals": false,
|
|
||||||
"noUnusedParameters": false
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"../source",
|
|
||||||
"type-tests.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -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<Forbidden extends Primitive> = Exclude<Primitive, Forbidden> | 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<number, number>` = `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<string>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotUndefinedUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.undefined(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<undefined>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotUndefinedGenericCheck = <T>(value: T) => {
|
|
||||||
isAssert.not.undefined(value);
|
|
||||||
const _: Exclude<T, undefined> = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const nullValue = null;
|
|
||||||
type Null = typeof nullValue;
|
|
||||||
|
|
||||||
const assertNotNullUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.null(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<Null>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotNullOrUndefinedCheck = (value: string | Null | undefined) => {
|
|
||||||
isAssert.not.nullOrUndefined(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<string>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotNullOrUndefinedUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.nullOrUndefined(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<Null | undefined>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotStringCheck = (value: string | number) => {
|
|
||||||
isAssert.not.string(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<number>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotStringUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.string(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<string>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotStringGenericCheck = <T>(value: T) => {
|
|
||||||
isAssert.not.string(value);
|
|
||||||
const _: Exclude<T, string> = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotBooleanUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.boolean(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<boolean>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotSymbolUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.symbol(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<symbol>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotBigintUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.bigint(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<bigint>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotPrimitiveUnknownCheck = (value: unknown) => {
|
|
||||||
isAssert.not.primitive(value);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
expectTypeOf(value).toEqualTypeOf<object>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotPrimitiveGenericCheck = <T>(value: T) => {
|
|
||||||
isAssert.not.primitive(value);
|
|
||||||
const _: Exclude<T, Primitive> = 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<UnknownNotPrimitive<Null | undefined>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotNamedStringExportCheck = (value: string | number) => {
|
|
||||||
assertNotString(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<number>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotNamedStringUnknownExportCheck = (value: unknown) => {
|
|
||||||
assertNotString(value);
|
|
||||||
expectTypeOf(value).toEqualTypeOf<UnknownNotPrimitive<string>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotNamedPrimitiveUnknownExportCheck = (value: unknown) => {
|
|
||||||
assertNotPrimitive(value);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
||||||
expectTypeOf(value).toEqualTypeOf<object>();
|
|
||||||
};
|
|
||||||
|
|
||||||
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, unknown> | 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, unknown> | 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, number> | 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, number> | string = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const assertNotSetDoesNotExistCheck = (value: Set<string> | 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> | 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<string | undefined>('🦄');
|
|
||||||
assertNotNullUnknownCheck('🦄');
|
|
||||||
assertNotNullOrUndefinedCheck('🦄');
|
|
||||||
assertNotNullOrUndefinedUnknownCheck('🦄');
|
|
||||||
assertNotStringCheck(1);
|
|
||||||
assertNotStringUnknownCheck(1);
|
|
||||||
assertNotStringGenericCheck<string | number>(1);
|
|
||||||
assertNotBooleanUnknownCheck(1);
|
|
||||||
assertNotSymbolUnknownCheck(1);
|
|
||||||
assertNotBigintUnknownCheck(1);
|
|
||||||
assertNotPrimitiveUnknownCheck({});
|
|
||||||
assertNotPrimitiveGenericCheck<string | {unicorn: true}>({unicorn: true});
|
|
||||||
assertNotNamedUndefinedExportCheck(0);
|
|
||||||
assertNotNamedNullOrUndefinedUnknownExportCheck('🦄');
|
|
||||||
assertNotNamedStringExportCheck(1);
|
|
||||||
assertNotNamedStringUnknownExportCheck(1);
|
|
||||||
assertNotNamedPrimitiveUnknownExportCheck({});
|
|
||||||
assertNotCallableDoesNotExistCheck('🦄');
|
|
||||||
assertNotNumberDoesNotExistCheck(Number.NaN);
|
|
||||||
assertNotIntegerDoesNotExistCheck(1.5);
|
|
||||||
assertNotObjectDoesNotExistCheck('🦄');
|
|
||||||
assertNotBlobDoesNotExistCheck('🦄');
|
|
||||||
assertNotMapDoesNotExistCheck('🦄');
|
|
||||||
assertNotSetDoesNotExistCheck('🦄');
|
|
||||||
assertNotDateDoesNotExistCheck('🦄');
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
{
|
{
|
||||||
"extends": "@sindresorhus/tsconfig",
|
"extends": "@sindresorhus/tsconfig",
|
||||||
"compilerOptions": {
|
|
||||||
"types": ["node"],
|
|
||||||
"rootDir": "source",
|
|
||||||
"allowImportingTsExtensions": true,
|
|
||||||
"rewriteRelativeImportExtensions": true
|
|
||||||
},
|
|
||||||
"include": [
|
"include": [
|
||||||
"source"
|
"source"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue