Compare commits
14 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7821031c66 | ||
|
|
a439305554 | ||
|
|
2d4956e634 | ||
|
|
48df5c429c | ||
|
|
13febb6b01 | ||
|
|
cb4ee0e92c | ||
|
|
54fc09406a | ||
|
|
63be5c0c19 | ||
|
|
ac46b5400d | ||
|
|
47415dc46a | ||
|
|
3b40955b02 | ||
|
|
faf700367e | ||
|
|
eff8e6b318 | ||
|
|
9bdcd9b57f |
12 changed files with 2648 additions and 1128 deletions
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
|
|
@ -10,10 +10,11 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
node-version:
|
||||
- 20
|
||||
- 24
|
||||
- 22
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
|
|
|
|||
9
AGENTS.md
Normal file
9
AGENTS.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# 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
CLAUDE.md
Symbolic link
1
CLAUDE.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
AGENTS.md
|
||||
51
package.json
51
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@sindresorhus/is",
|
||||
"version": "7.1.1",
|
||||
"version": "8.1.0",
|
||||
"description": "Type check values",
|
||||
"license": "MIT",
|
||||
"repository": "sindresorhus/is",
|
||||
|
|
@ -17,11 +17,11 @@
|
|||
},
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=22"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "del distribution && tsc",
|
||||
"test": "tsc --noEmit && xo && ava",
|
||||
"test": "tsc --noEmit && tsc --project test/tsconfig.json --noEmit && xo && node --experimental-transform-types --test test/test.ts",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"files": [
|
||||
|
|
@ -51,31 +51,26 @@
|
|||
"typeguards",
|
||||
"types"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@sindresorhus/tsconfig": "^6.0.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/zen-observable": "^0.8.7",
|
||||
"ava": "^6.1.3",
|
||||
"del-cli": "^5.1.0",
|
||||
"expect-type": "^0.19.0",
|
||||
"jsdom": "^24.1.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"tempy": "^3.1.0",
|
||||
"tsimp": "2.0.11",
|
||||
"typescript": "5.5.3",
|
||||
"xo": "^0.58.0",
|
||||
"zen-observable": "^0.10.0"
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"ava": {
|
||||
"environmentVariables": {
|
||||
"TSIMP_DIAG": "error"
|
||||
},
|
||||
"extensions": {
|
||||
"ts": "module"
|
||||
},
|
||||
"nodeArguments": [
|
||||
"--import=tsimp/import"
|
||||
]
|
||||
"devDependencies": {
|
||||
"@sindresorhus/tsconfig": "^8.1.0",
|
||||
"@types/jsdom": "^28.0.1",
|
||||
"@types/node": "^25.5.2",
|
||||
"@types/zen-observable": "^0.8.7",
|
||||
"del-cli": "^7.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"jsdom": "^29.0.2",
|
||||
"rxjs": "^7.8.2",
|
||||
"tempy": "^3.2.0",
|
||||
"typescript": "6.0.2",
|
||||
"xo": "^2.0.2",
|
||||
"zen-observable": "^0.10.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
127
readme.md
127
readme.md
|
|
@ -130,6 +130,17 @@ is.array(value); // Validate `value` is an array.
|
|||
is.array(value, is.number); // Validate `value` is an array and all of its items are numbers.
|
||||
```
|
||||
|
||||
##### .arrayOf(predicate)
|
||||
|
||||
Returns a type guard that checks if `value` is an array where every item matches the predicate. Useful for composing with other methods.
|
||||
|
||||
```js
|
||||
const isStringArray = is.arrayOf(is.string);
|
||||
|
||||
isStringArray(['a', 'b']); //=> true
|
||||
isStringArray(['a', 1]); //=> false
|
||||
```
|
||||
|
||||
##### .function(value)
|
||||
|
||||
##### .buffer(value)
|
||||
|
|
@ -463,6 +474,10 @@ function foo() {
|
|||
foo();
|
||||
```
|
||||
|
||||
##### .finiteNumber(value)
|
||||
|
||||
Check if `value` is a number and is finite. Excludes `Infinity` and `-Infinity`.
|
||||
|
||||
##### .positiveNumber(value)
|
||||
|
||||
Check if `value` is a number and is more than 0.
|
||||
|
|
@ -471,6 +486,22 @@ Check if `value` is a number and is more than 0.
|
|||
|
||||
Check if `value` is a number and is less than 0.
|
||||
|
||||
##### .nonNegativeNumber(value)
|
||||
|
||||
Check if `value` is a number and is 0 or more.
|
||||
|
||||
##### .positiveInteger(value)
|
||||
|
||||
Check if `value` is an integer and is more than 0.
|
||||
|
||||
##### .negativeInteger(value)
|
||||
|
||||
Check if `value` is an integer and is less than 0.
|
||||
|
||||
##### .nonNegativeInteger(value)
|
||||
|
||||
Check if `value` is an integer and is 0 or more.
|
||||
|
||||
##### .inRange(value, range)
|
||||
|
||||
Check if `value` (number) is in the given `range`. The range is an array of two values, lower bound and upper bound, in no specific order.
|
||||
|
|
@ -575,6 +606,31 @@ is.any([is.boolean, is.number], 'unicorns', [], new Map());
|
|||
//=> false
|
||||
```
|
||||
|
||||
##### .any(predicate[])
|
||||
|
||||
Using an array of `predicate[]` without values, returns a combined type guard that checks if a value matches **any** of the predicates:
|
||||
|
||||
```js
|
||||
const isStringOrNumber = is.any([is.string, is.number]);
|
||||
|
||||
isStringOrNumber('hello');
|
||||
//=> true
|
||||
|
||||
isStringOrNumber(123);
|
||||
//=> true
|
||||
|
||||
isStringOrNumber(true);
|
||||
//=> false
|
||||
```
|
||||
|
||||
This is useful for composing with other methods like `is.optional`:
|
||||
|
||||
```js
|
||||
is.optional(value, is.any([is.string, is.number]));
|
||||
```
|
||||
|
||||
An empty predicate array currently returns a predicate that always returns `false`. This will throw in the next major release.
|
||||
|
||||
##### .all(predicate, ...values)
|
||||
|
||||
Returns `true` if **all** of the input `values` returns true in the `predicate`:
|
||||
|
|
@ -587,6 +643,28 @@ is.all(is.string, '🦄', [], 'unicorns');
|
|||
//=> false
|
||||
```
|
||||
|
||||
##### .all(predicate[])
|
||||
|
||||
Using an array of `predicate[]` without values, returns a combined type guard that checks if a value matches **all** of the predicates:
|
||||
|
||||
```js
|
||||
const isArrayAndNonEmpty = is.all([is.array, is.nonEmptyArray]);
|
||||
|
||||
isArrayAndNonEmpty(['hello']);
|
||||
//=> true
|
||||
|
||||
isArrayAndNonEmpty([]);
|
||||
//=> false
|
||||
```
|
||||
|
||||
This is useful for composing with other methods like `is.optional`:
|
||||
|
||||
```js
|
||||
is.optional(value, is.all([is.object, is.plainObject]));
|
||||
```
|
||||
|
||||
An empty predicate array currently returns a predicate that always returns `true`. This will throw in the next major release.
|
||||
|
||||
##### .optional(value, predicate)
|
||||
|
||||
Returns `true` if `value` is `undefined` or satisfies the given `predicate`.
|
||||
|
|
@ -602,6 +680,17 @@ is.optional(123, is.string);
|
|||
//=> false
|
||||
```
|
||||
|
||||
##### .oneOf(values)
|
||||
|
||||
Returns a type guard that checks if `value` is one of the given `values`. Best used with `as const` for precise type narrowing.
|
||||
|
||||
```ts
|
||||
const isDirection = is.oneOf(['north', 'south', 'east', 'west'] as const);
|
||||
|
||||
isDirection('north'); //=> true
|
||||
isDirection('up'); //=> false
|
||||
```
|
||||
|
||||
##### .validDate(value)
|
||||
|
||||
Returns `true` if the value is a valid date.
|
||||
|
|
@ -697,6 +786,44 @@ handleMovieRatingApiResponse({rating: 0.87, title: 'The Matrix'});
|
|||
handleMovieRatingApiResponse({rating: '🦄'});
|
||||
```
|
||||
|
||||
### Negative assertion
|
||||
|
||||
Asserts that `value` is not the specified type. Only exact, type-safe negative assertions are exposed.
|
||||
|
||||
Supported assertions:
|
||||
|
||||
- `assert.not.undefined(value)`
|
||||
- `assert.not.null(value)`
|
||||
- `assert.not.nullOrUndefined(value)`
|
||||
- `assert.not.string(value)`
|
||||
- `assert.not.boolean(value)`
|
||||
- `assert.not.symbol(value)`
|
||||
- `assert.not.bigint(value)`
|
||||
- `assert.not.primitive(value)`
|
||||
|
||||
This intentionally excludes checks that cannot produce a safe TypeScript complement: `number` because `is.number` rejects `NaN`, refinements such as `integer` and `validDate`, and branded structural object checks such as `map` and `date`. Broad object checks such as `object` are also excluded to keep negative assertions limited to primitive and nullish types.
|
||||
|
||||
```ts
|
||||
import {assert} from '@sindresorhus/is';
|
||||
|
||||
const value: string | undefined = getValue();
|
||||
|
||||
assert.not.undefined(value);
|
||||
// Throws if `value` is `undefined`. Otherwise, `value` is now typed as `string`.
|
||||
```
|
||||
|
||||
For `unknown` input, exact negative assertions narrow to the remaining representable type:
|
||||
|
||||
```ts
|
||||
const value: unknown = getValue();
|
||||
|
||||
assert.not.nullOrUndefined(value);
|
||||
// `value` is now typed as non-nullish.
|
||||
|
||||
assert.not.primitive(value);
|
||||
// `value` is now typed as `object`.
|
||||
```
|
||||
|
||||
### Optional assertion
|
||||
|
||||
Asserts that `value` is `undefined` or satisfies the provided `assertion`.
|
||||
|
|
|
|||
473
source/index.ts
473
source/index.ts
|
|
@ -1,18 +1,33 @@
|
|||
import type {
|
||||
ArrayLike,
|
||||
Class,
|
||||
EvenInteger,
|
||||
Falsy,
|
||||
FiniteNumber,
|
||||
Integer,
|
||||
NaN as NaNType,
|
||||
NegativeInfinity,
|
||||
NegativeInteger,
|
||||
NegativeNumber,
|
||||
NodeStream,
|
||||
NonEmptyString,
|
||||
NonNegativeInteger,
|
||||
NonNegativeNumber,
|
||||
ObservableLike,
|
||||
OddInteger,
|
||||
Predicate,
|
||||
Primitive,
|
||||
PositiveInfinity,
|
||||
PositiveInteger,
|
||||
PositiveNumber,
|
||||
SafeInteger,
|
||||
TypedArray,
|
||||
UrlString,
|
||||
ValidLength,
|
||||
WeakRef,
|
||||
Whitespace,
|
||||
} from './types.js';
|
||||
import {keysOf} from './utilities.js';
|
||||
} from './types.ts';
|
||||
import {keysOf} from './utilities.ts';
|
||||
|
||||
// From type-fest.
|
||||
type ExtractFromGlobalConstructors<Name extends string> =
|
||||
|
|
@ -22,6 +37,15 @@ type ExtractFromGlobalConstructors<Name extends string> =
|
|||
|
||||
type NodeBuffer = ExtractFromGlobalConstructors<'Buffer'>;
|
||||
|
||||
type NumericGuardResult<Input, Branded extends number> =
|
||||
(
|
||||
unknown extends Input
|
||||
? Branded
|
||||
: Input extends number
|
||||
? Branded & Input
|
||||
: number
|
||||
) & Input;
|
||||
|
||||
const typedArrayTypeNames = [
|
||||
'Int8Array',
|
||||
'Uint8Array',
|
||||
|
|
@ -99,6 +123,7 @@ function isPrimitiveTypeName(name: unknown): name is PrimitiveTypeName {
|
|||
export type TypeName = ObjectTypeName | PrimitiveTypeName;
|
||||
|
||||
const assertionTypeDescriptions = [
|
||||
'bound Function',
|
||||
'positive number',
|
||||
'negative number',
|
||||
'Class',
|
||||
|
|
@ -133,7 +158,13 @@ const assertionTypeDescriptions = [
|
|||
'non-empty map',
|
||||
'PropertyKey',
|
||||
'even integer',
|
||||
'finite number',
|
||||
'negative integer',
|
||||
'non-negative integer',
|
||||
'non-negative number',
|
||||
'odd integer',
|
||||
'positive integer',
|
||||
'safe integer',
|
||||
'T',
|
||||
'in range',
|
||||
'predicate returns truthy for any value',
|
||||
|
|
@ -150,7 +181,7 @@ export type AssertionTypeDescription = typeof assertionTypeDescriptions[number];
|
|||
const getObjectType = (value: unknown): ObjectTypeName | undefined => {
|
||||
const objectTypeName = Object.prototype.toString.call(value).slice(8, -1);
|
||||
|
||||
if (/HTML\w+Element/.test(objectTypeName) && isHtmlElement(value)) {
|
||||
if (/HTML\w+Element/v.test(objectTypeName) && isHtmlElement(value)) {
|
||||
return 'HTMLElement';
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +197,7 @@ function detect(value: unknown): TypeName {
|
|||
return 'null';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
||||
switch (typeof value) {
|
||||
case 'undefined': {
|
||||
return 'undefined';
|
||||
|
|
@ -211,7 +243,7 @@ function detect(value: unknown): TypeName {
|
|||
}
|
||||
|
||||
const tagType = getObjectType(value);
|
||||
if (tagType && tagType !== 'Object') {
|
||||
if (tagType !== undefined && tagType !== 'Object') {
|
||||
return tagType;
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +251,7 @@ function detect(value: unknown): TypeName {
|
|||
return 'Promise';
|
||||
}
|
||||
|
||||
if (value instanceof String || value instanceof Boolean || value instanceof Number) {
|
||||
if (isBoxedPrimitiveObject(value)) {
|
||||
throw new TypeError('Please don\'t use object wrappers for primitive types');
|
||||
}
|
||||
|
||||
|
|
@ -230,6 +262,23 @@ function hasPromiseApi<T = unknown>(value: unknown): value is Promise<T> {
|
|||
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(
|
||||
detect,
|
||||
{
|
||||
|
|
@ -238,6 +287,7 @@ const is = Object.assign(
|
|||
array: isArray,
|
||||
arrayBuffer: isArrayBuffer,
|
||||
arrayLike: isArrayLike,
|
||||
arrayOf: isArrayOf,
|
||||
asyncFunction: isAsyncFunction,
|
||||
asyncGenerator: isAsyncGenerator,
|
||||
asyncGeneratorFunction: isAsyncGeneratorFunction,
|
||||
|
|
@ -264,6 +314,7 @@ const is = Object.assign(
|
|||
error: isError,
|
||||
evenInteger: isEvenInteger,
|
||||
falsy: isFalsy,
|
||||
finiteNumber: isFiniteNumber,
|
||||
float32Array: isFloat32Array,
|
||||
float64Array: isFloat64Array,
|
||||
formData: isFormData,
|
||||
|
|
@ -281,6 +332,7 @@ const is = Object.assign(
|
|||
map: isMap,
|
||||
nan: isNan,
|
||||
nativePromise: isNativePromise,
|
||||
negativeInteger: isNegativeInteger,
|
||||
negativeNumber: isNegativeNumber,
|
||||
nodeStream: isNodeStream,
|
||||
nonEmptyArray: isNonEmptyArray,
|
||||
|
|
@ -289,6 +341,8 @@ const is = Object.assign(
|
|||
nonEmptySet: isNonEmptySet,
|
||||
nonEmptyString: isNonEmptyString,
|
||||
nonEmptyStringAndNotWhitespace: isNonEmptyStringAndNotWhitespace,
|
||||
nonNegativeInteger: isNonNegativeInteger,
|
||||
nonNegativeNumber: isNonNegativeNumber,
|
||||
null: isNull,
|
||||
nullOrUndefined: isNullOrUndefined,
|
||||
number: isNumber,
|
||||
|
|
@ -296,7 +350,9 @@ const is = Object.assign(
|
|||
object: isObject,
|
||||
observable: isObservable,
|
||||
oddInteger: isOddInteger,
|
||||
oneOf: isOneOf,
|
||||
plainObject: isPlainObject,
|
||||
positiveInteger: isPositiveInteger,
|
||||
positiveNumber: isPositiveNumber,
|
||||
primitive: isPrimitive,
|
||||
promise: isPromise,
|
||||
|
|
@ -332,15 +388,81 @@ function isAbsoluteModule2(remainder: 0 | 1) {
|
|||
return (value: unknown): value is number => isInteger(value) && Math.abs(value % 2) === remainder;
|
||||
}
|
||||
|
||||
export function isAll(predicate: Predicate, ...values: unknown[]): boolean {
|
||||
return predicateOnArray(Array.prototype.every, predicate, values);
|
||||
type TypeGuard<T> = (value: unknown) => value is T;
|
||||
|
||||
function validatePredicateArray(predicateArray: readonly Predicate[], allowEmpty: boolean) {
|
||||
if (predicateArray.length === 0) {
|
||||
if (allowEmpty) {
|
||||
// Next major release: throw for empty predicate arrays to avoid vacuous results.
|
||||
// throw new TypeError('Invalid predicate array');
|
||||
} else {
|
||||
throw new TypeError('Invalid predicate array');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (const predicate of predicateArray) {
|
||||
validatePredicate(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
export function isAny(predicate: Predicate | Predicate[], ...values: unknown[]): boolean {
|
||||
const predicates = isArray(predicate) ? predicate : [predicate];
|
||||
return predicates.some(singlePredicate =>
|
||||
predicateOnArray(Array.prototype.some, singlePredicate, values),
|
||||
);
|
||||
function validatePredicate(predicate: Predicate) {
|
||||
if (!isFunction(predicate)) {
|
||||
throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Predicate factory overloads - return a type guard when called with only predicates
|
||||
export function isAll<T1>(predicates: [TypeGuard<T1>]): TypeGuard<T1>;
|
||||
export function isAll<T1, T2>(predicates: [TypeGuard<T1>, TypeGuard<T2>]): TypeGuard<T1 & T2>;
|
||||
export function isAll<T1, T2, T3>(predicates: [TypeGuard<T1>, TypeGuard<T2>, TypeGuard<T3>]): TypeGuard<T1 & T2 & T3>;
|
||||
export function isAll<T1, T2, T3, T4>(predicates: [TypeGuard<T1>, TypeGuard<T2>, TypeGuard<T3>, TypeGuard<T4>]): TypeGuard<T1 & T2 & T3 & T4>;
|
||||
export function isAll<T1, T2, T3, T4, T5>(predicates: [TypeGuard<T1>, TypeGuard<T2>, TypeGuard<T3>, TypeGuard<T4>, TypeGuard<T5>]): TypeGuard<T1 & T2 & T3 & T4 & T5>;
|
||||
export function isAll(predicates: ReadonlyArray<TypeGuard<unknown>>): TypeGuard<unknown>;
|
||||
export function isAll(predicates: readonly Predicate[]): Predicate;
|
||||
// Evaluator overload - check if all values match the predicate
|
||||
export function isAll(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean;
|
||||
export function isAll(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean | Predicate {
|
||||
if (Array.isArray(predicate)) {
|
||||
const predicateArray = predicate as readonly Predicate[];
|
||||
validatePredicateArray(predicateArray, values.length === 0);
|
||||
|
||||
const combinedPredicate = (value: unknown) => predicateArray.every(singlePredicate => singlePredicate(value));
|
||||
if (values.length === 0) {
|
||||
return combinedPredicate;
|
||||
}
|
||||
|
||||
return predicateOnArray(Array.prototype.every, combinedPredicate, values);
|
||||
}
|
||||
|
||||
return predicateOnArray(Array.prototype.every, predicate as Predicate, values);
|
||||
}
|
||||
|
||||
// Predicate factory overloads - return a type guard when called with only predicates
|
||||
export function isAny<T1>(predicates: [TypeGuard<T1>]): TypeGuard<T1>;
|
||||
export function isAny<T1, T2>(predicates: [TypeGuard<T1>, TypeGuard<T2>]): TypeGuard<T1 | T2>;
|
||||
export function isAny<T1, T2, T3>(predicates: [TypeGuard<T1>, TypeGuard<T2>, TypeGuard<T3>]): TypeGuard<T1 | T2 | T3>;
|
||||
export function isAny<T1, T2, T3, T4>(predicates: [TypeGuard<T1>, TypeGuard<T2>, TypeGuard<T3>, TypeGuard<T4>]): TypeGuard<T1 | T2 | T3 | T4>;
|
||||
export function isAny<T1, T2, T3, T4, T5>(predicates: [TypeGuard<T1>, TypeGuard<T2>, TypeGuard<T3>, TypeGuard<T4>, TypeGuard<T5>]): TypeGuard<T1 | T2 | T3 | T4 | T5>;
|
||||
export function isAny(predicates: ReadonlyArray<TypeGuard<unknown>>): TypeGuard<unknown>;
|
||||
export function isAny(predicates: readonly Predicate[]): Predicate;
|
||||
// Evaluator overload - check if any value matches any predicate
|
||||
export function isAny(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean;
|
||||
export function isAny(predicate: Predicate | readonly Predicate[], ...values: unknown[]): boolean | Predicate {
|
||||
if (Array.isArray(predicate)) {
|
||||
const predicateArray = predicate as readonly Predicate[];
|
||||
validatePredicateArray(predicateArray, values.length === 0);
|
||||
|
||||
const combinedPredicate = (value: unknown) => predicateArray.some(singlePredicate => singlePredicate(value));
|
||||
if (values.length === 0) {
|
||||
return combinedPredicate;
|
||||
}
|
||||
|
||||
return predicateOnArray(Array.prototype.some, combinedPredicate, values);
|
||||
}
|
||||
|
||||
return predicateOnArray(Array.prototype.some, predicate as Predicate, values);
|
||||
}
|
||||
|
||||
export function isOptional<T>(value: unknown, predicate: (value: unknown) => value is T): value is T | undefined {
|
||||
|
|
@ -368,6 +490,10 @@ export function isArrayLike<T = unknown>(value: unknown): value is ArrayLike<T>
|
|||
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>) {
|
||||
return getObjectType(value) === 'AsyncFunction';
|
||||
}
|
||||
|
|
@ -404,7 +530,7 @@ export function isBoolean(value: unknown): value is boolean {
|
|||
return value === true || value === false;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
export function isBoundFunction(value: unknown): value is Function {
|
||||
return isFunction(value) && !Object.hasOwn(value, 'prototype');
|
||||
}
|
||||
|
|
@ -413,12 +539,12 @@ export function isBoundFunction(value: unknown): value is Function {
|
|||
Note: [Prefer using `Uint8Array` instead of `Buffer`.](https://sindresorhus.com/blog/goodbye-nodejs-buffer)
|
||||
*/
|
||||
export function isBuffer(value: unknown): value is NodeBuffer {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
return (value as any)?.constructor?.isBuffer?.(value) ?? false;
|
||||
}
|
||||
|
||||
export function isClass<T = unknown>(value: unknown): value is Class<T> {
|
||||
return isFunction(value) && /^class(\s+|{)/.test(value.toString());
|
||||
return isFunction(value) && /^class(?:\s+|\{)/v.test(value.toString());
|
||||
}
|
||||
|
||||
export function isDataView(value: unknown): value is DataView {
|
||||
|
|
@ -446,7 +572,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> {
|
||||
return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0;
|
||||
return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0;
|
||||
}
|
||||
|
||||
export function isEmptySet(value: unknown): value is Set<never> {
|
||||
|
|
@ -462,16 +588,31 @@ export function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitesp
|
|||
}
|
||||
|
||||
export function isEnumCase<T = unknown>(value: unknown, targetEnum: T): value is T[keyof T] {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
return Object.values(targetEnum as any).includes(value as string);
|
||||
// Numeric enums have reverse mappings (e.g. `Direction[0] = "Up"`), so their runtime object contains both `{ Up: 0 }` and `{ "0": "Up" }`. Filtering out entries that round-trip like a canonical number and point back to an own property leaves only actual enum member values.
|
||||
const enumObject = targetEnum as Record<PropertyKey, unknown>;
|
||||
|
||||
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 {
|
||||
// TODO: Use `Error.isError` when targeting Node.js 24.`
|
||||
// TODO: Use `Error.isError` when targeting Node.js 24.
|
||||
return getObjectType(value) === 'Error';
|
||||
}
|
||||
|
||||
export function isEvenInteger(value: unknown): value is number {
|
||||
// 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<Input>(value: Input): value is NumericGuardResult<Input, EvenInteger>;
|
||||
export function isEvenInteger(value: unknown): boolean {
|
||||
return isAbsoluteModule2(0)(value);
|
||||
}
|
||||
|
||||
|
|
@ -480,6 +621,11 @@ export function isFalsy(value: unknown): value is Falsy {
|
|||
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.
|
||||
|
||||
export function isFloat32Array(value: unknown): value is Float32Array {
|
||||
|
|
@ -494,7 +640,7 @@ export function isFormData(value: unknown): value is FormData {
|
|||
return getObjectType(value) === 'FormData';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
export function isFunction(value: unknown): value is Function {
|
||||
return typeof value === 'function';
|
||||
}
|
||||
|
|
@ -507,11 +653,9 @@ export function isGeneratorFunction(value: unknown): value is GeneratorFunction
|
|||
return getObjectType(value) === 'GeneratorFunction';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const NODE_TYPE_ELEMENT = 1;
|
||||
const NODE_TYPE_ELEMENT = 1; // eslint-disable-line @typescript-eslint/naming-convention
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const DOM_PROPERTIES_TO_CHECK: Array<(keyof HTMLElement)> = [
|
||||
const DOM_PROPERTIES_TO_CHECK: Array<(keyof HTMLElement)> = [ // eslint-disable-line @typescript-eslint/naming-convention
|
||||
'innerHTML',
|
||||
'ownerDocument',
|
||||
'style',
|
||||
|
|
@ -527,7 +671,8 @@ export function isHtmlElement(value: unknown): value is HTMLElement {
|
|||
&& DOM_PROPERTIES_TO_CHECK.every(property => property in value);
|
||||
}
|
||||
|
||||
export function isInfinite(value: unknown): value is number {
|
||||
export function isInfinite<Input>(value: Input): value is NumericGuardResult<Input, PositiveInfinity | NegativeInfinity>;
|
||||
export function isInfinite(value: unknown): boolean {
|
||||
return value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY;
|
||||
}
|
||||
|
||||
|
|
@ -537,6 +682,10 @@ export function isInRange(value: number, range: number | [number, number]): valu
|
|||
}
|
||||
|
||||
if (isArray(range) && range.length === 2) {
|
||||
if (Number.isNaN(range[0]) || Number.isNaN(range[1])) {
|
||||
throw new TypeError(`Invalid range: ${JSON.stringify(range)}`);
|
||||
}
|
||||
|
||||
return value >= Math.min(...range) && value <= Math.max(...range);
|
||||
}
|
||||
|
||||
|
|
@ -555,7 +704,8 @@ export function isInt8Array(value: unknown): value is Int8Array {
|
|||
return getObjectType(value) === 'Int8Array';
|
||||
}
|
||||
|
||||
export function isInteger(value: unknown): value is number {
|
||||
export function isInteger<Input>(value: Input): value is NumericGuardResult<Input, Integer>;
|
||||
export function isInteger(value: unknown): boolean {
|
||||
return Number.isInteger(value);
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +717,8 @@ export function isMap<Key = unknown, Value = unknown>(value: unknown): value is
|
|||
return getObjectType(value) === 'Map';
|
||||
}
|
||||
|
||||
export function isNan(value: unknown) {
|
||||
export function isNan<Input>(value: Input): value is NumericGuardResult<Input, NaNType>;
|
||||
export function isNan(value: unknown): boolean {
|
||||
return Number.isNaN(value);
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +726,13 @@ export function isNativePromise<T = unknown>(value: unknown): value is Promise<T
|
|||
return getObjectType(value) === 'Promise';
|
||||
}
|
||||
|
||||
export function isNegativeNumber(value: unknown): value is number {
|
||||
export function isNegativeInteger<Input>(value: Input): value is NumericGuardResult<Input, NegativeInteger>;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -594,7 +751,7 @@ export function isNonEmptyMap<Key = unknown, Value = unknown>(value: unknown): v
|
|||
// TODO: Use `not` operator here to remove `Map` and `Set` from type guard:
|
||||
// - https://github.com/Microsoft/TypeScript/pull/29317
|
||||
export function isNonEmptyObject<Key extends keyof any = string, Value = unknown>(value: unknown): value is Record<Key, Value> {
|
||||
return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0;
|
||||
return isObject(value) && !isFunction(value) && !isArray(value) && !isMap(value) && !isSet(value) && Object.keys(value).length > 0;
|
||||
}
|
||||
|
||||
export function isNonEmptySet<T = unknown>(value: unknown): value is Set<T> {
|
||||
|
|
@ -611,12 +768,22 @@ export function isNonEmptyStringAndNotWhitespace(value: unknown): value is NonEm
|
|||
return isString(value) && !isEmptyStringOrWhitespace(value);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function isNonNegativeInteger<Input>(value: Input): value is NumericGuardResult<Input, NonNegativeInteger>;
|
||||
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 {
|
||||
return value === null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function isNullOrUndefined(value: unknown): value is null | undefined {
|
||||
return isNull(value) || isUndefined(value);
|
||||
}
|
||||
|
|
@ -626,10 +793,10 @@ export function isNumber(value: unknown): value is number {
|
|||
}
|
||||
|
||||
export function isNumericString(value: unknown): value is `${number}` {
|
||||
return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value));
|
||||
return isString(value) && !isEmptyStringOrWhitespace(value) && value === value.trim() && !Number.isNaN(Number(value));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function isObject(value: unknown): value is object {
|
||||
return !isNull(value) && (typeof value === 'object' || isFunction(value));
|
||||
}
|
||||
|
|
@ -639,12 +806,12 @@ export function isObservable(value: unknown): value is ObservableLike {
|
|||
return false;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-use-extend-native/no-use-extend-native, @typescript-eslint/no-unsafe-call
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
if (Symbol.observable !== undefined && value === (value as any)[Symbol.observable]?.()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
if (value === (value as any)['@@observable']?.()) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -652,10 +819,15 @@ export function isObservable(value: unknown): value is ObservableLike {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function isOddInteger(value: unknown): value is number {
|
||||
export function isOddInteger<Input>(value: Input): value is NumericGuardResult<Input, OddInteger>;
|
||||
export function isOddInteger(value: unknown): boolean {
|
||||
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> {
|
||||
// From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
|
||||
if (typeof value !== 'object' || value === null) {
|
||||
|
|
@ -668,7 +840,13 @@ 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);
|
||||
}
|
||||
|
||||
export function isPositiveNumber(value: unknown): value is number {
|
||||
export function isPositiveInteger<Input>(value: Input): value is NumericGuardResult<Input, PositiveInteger>;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -680,7 +858,7 @@ export function isPromise<T = unknown>(value: unknown): value is Promise<T> {
|
|||
return isNativePromise(value) || hasPromiseApi(value);
|
||||
}
|
||||
|
||||
// `PropertyKey` is any value that can be used as an object key (string, number, or symbol)
|
||||
// `PropertyKey` is any value that can be used as an object key (string, number, or symbol). Note: NaN is technically `typeof 'number'` and thus fits TypeScript's `PropertyKey`, but we intentionally exclude it here because using NaN as a property key is almost always a mistake.
|
||||
export function isPropertyKey(value: unknown): value is PropertyKey {
|
||||
return isAny([isString, isNumber, isSymbol], value);
|
||||
}
|
||||
|
|
@ -689,7 +867,8 @@ export function isRegExp(value: unknown): value is RegExp {
|
|||
return getObjectType(value) === 'RegExp';
|
||||
}
|
||||
|
||||
export function isSafeInteger(value: unknown): value is number {
|
||||
export function isSafeInteger<Input>(value: Input): value is NumericGuardResult<Input, SafeInteger>;
|
||||
export function isSafeInteger(value: unknown): boolean {
|
||||
return Number.isSafeInteger(value);
|
||||
}
|
||||
|
||||
|
|
@ -715,10 +894,8 @@ export function isTruthy<T>(value: T | Falsy): value is T {
|
|||
return Boolean(value);
|
||||
}
|
||||
|
||||
type TypeGuard<T> = (value: unknown) => value is T;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type ResolveTypesOfTypeGuardsTuple<TypeGuardsOfT, ResultOfT extends unknown[] = [] > =
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
type ResolveTypesOfTypeGuardsTuple<TypeGuardsOfT, ResultOfT extends unknown[] = []> =
|
||||
TypeGuardsOfT extends [TypeGuard<infer U>, ...infer TOthers]
|
||||
? ResolveTypesOfTypeGuardsTuple<TOthers, [...ResultOfT, U]>
|
||||
: TypeGuardsOfT extends undefined[]
|
||||
|
|
@ -783,35 +960,34 @@ export function isValidDate(value: unknown): value is Date {
|
|||
return isDate(value) && !isNan(Number(value));
|
||||
}
|
||||
|
||||
export function isValidLength(value: unknown): value is number {
|
||||
export function isValidLength<Input>(value: Input): value is NumericGuardResult<Input, ValidLength>;
|
||||
export function isValidLength(value: unknown): boolean {
|
||||
return isSafeInteger(value) && value >= 0;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function isWeakMap<Key extends object = object, Value = unknown>(value: unknown): value is WeakMap<Key, Value> {
|
||||
return getObjectType(value) === 'WeakMap';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function isWeakRef(value: unknown): value is WeakRef<object> {
|
||||
return getObjectType(value) === 'WeakRef';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function isWeakSet(value: unknown): value is WeakSet<object> {
|
||||
return getObjectType(value) === 'WeakSet';
|
||||
}
|
||||
|
||||
export function isWhitespaceString(value: unknown): value is Whitespace {
|
||||
return isString(value) && /^\s+$/.test(value);
|
||||
return isString(value) && /^\s+$/v.test(value);
|
||||
}
|
||||
|
||||
type ArrayMethod = (function_: (value: unknown, index: number, array: unknown[]) => boolean, thisArgument?: unknown) => boolean;
|
||||
|
||||
function predicateOnArray(method: ArrayMethod, predicate: Predicate, values: unknown[]) {
|
||||
if (!isFunction(predicate)) {
|
||||
throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`);
|
||||
}
|
||||
validatePredicate(predicate);
|
||||
|
||||
if (values.length === 0) {
|
||||
throw new TypeError('Invalid number of values');
|
||||
|
|
@ -824,6 +1000,17 @@ function typeErrorMessage(description: AssertionTypeDescription, value: unknown)
|
|||
return `Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`;
|
||||
}
|
||||
|
||||
function typeErrorMessageNot(description: AssertionTypeDescription, value: unknown): string {
|
||||
return `Expected value which is not \`${description}\`, received value of type \`${is(value)}\`.`;
|
||||
}
|
||||
|
||||
type NotAssertionResult<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[] {
|
||||
// eslint-disable-next-line unicorn/prefer-spread
|
||||
return Array.from(new Set(values));
|
||||
|
|
@ -839,17 +1026,24 @@ function typeErrorMessageMultipleValues(expectedType: AssertionTypeDescription |
|
|||
}
|
||||
|
||||
// Type assertions have to be declared with an explicit type.
|
||||
// Keep assertion outputs unbranded even when the corresponding `is.*` guard uses a branded subtype.
|
||||
// The brands exist to preserve useful false-branch narrowing for type guards on `number` inputs, which does not apply to `asserts`.
|
||||
type Assert = {
|
||||
// Unknowns.
|
||||
undefined: (value: unknown, message?: string) => asserts value is undefined;
|
||||
string: (value: unknown, message?: string) => asserts value is string;
|
||||
number: (value: unknown, message?: string) => asserts value is number;
|
||||
finiteNumber: (value: unknown, message?: string) => asserts value is number;
|
||||
positiveNumber: (value: unknown, message?: string) => asserts value is number;
|
||||
negativeInteger: (value: unknown, message?: string) => asserts value is number;
|
||||
negativeNumber: (value: unknown, message?: string) => asserts value is number;
|
||||
nonNegativeInteger: (value: unknown, message?: string) => asserts value is number;
|
||||
nonNegativeNumber: (value: unknown, message?: string) => asserts value is number;
|
||||
positiveInteger: (value: unknown, message?: string) => asserts value is number;
|
||||
bigint: (value: unknown, message?: string) => asserts value is bigint;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
function: (value: unknown, message?: string) => asserts value is Function;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
null: (value: unknown, message?: string) => asserts value is null;
|
||||
class: <T = unknown>(value: unknown, message?: string) => asserts value is Class<T>;
|
||||
boolean: (value: unknown, message?: string) => asserts value is boolean;
|
||||
|
|
@ -858,7 +1052,7 @@ type Assert = {
|
|||
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;
|
||||
blob: (value: unknown, message?: string) => asserts value is Blob;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
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>;
|
||||
iterable: <T = unknown>(value: unknown, message?: string) => asserts value is Iterable<T>;
|
||||
|
|
@ -869,20 +1063,20 @@ type Assert = {
|
|||
promise: <T = unknown>(value: unknown, message?: string) => asserts value is Promise<T>;
|
||||
generatorFunction: (value: unknown, message?: string) => asserts value is GeneratorFunction;
|
||||
asyncGeneratorFunction: (value: unknown, message?: string) => asserts value is AsyncGeneratorFunction;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
asyncFunction: (value: unknown, message?: string) => asserts value is Function;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
boundFunction: (value: unknown, message?: string) => asserts value is Function;
|
||||
regExp: (value: unknown, message?: string) => asserts value is RegExp;
|
||||
date: (value: unknown, message?: string) => asserts value is Date;
|
||||
error: (value: unknown, message?: string) => asserts value is Error;
|
||||
map: <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>;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
weakMap: <Key extends object = object, Value = unknown>(value: unknown, message?: string) => asserts value is WeakMap<Key, Value>;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
weakSet: <T extends object = object>(value: unknown, message?: string) => asserts value is WeakSet<T>;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
weakRef: <T extends object = object>(value: unknown, message?: string) => asserts value is WeakRef<T>;
|
||||
int8Array: (value: unknown, message?: string) => asserts value is Int8Array;
|
||||
uint8Array: (value: unknown, message?: string) => asserts value is Uint8Array;
|
||||
|
|
@ -942,9 +1136,11 @@ type Assert = {
|
|||
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;
|
||||
|
||||
not: NotAssert;
|
||||
|
||||
// Variadic functions.
|
||||
any: (predicate: Predicate | Predicate[], ...values: unknown[]) => void | never;
|
||||
all: (predicate: Predicate, ...values: unknown[]) => void | never;
|
||||
any: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never;
|
||||
all: (predicate: Predicate | readonly Predicate[], ...values: unknown[]) => void | never;
|
||||
|
||||
/**
|
||||
Asserts that `value` is `undefined` or satisfies the provided `assertion`.
|
||||
|
|
@ -954,9 +1150,58 @@ type Assert = {
|
|||
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 = {
|
||||
all: assertAll,
|
||||
any: assertAny,
|
||||
not: notAssertions,
|
||||
optional: assertOptional,
|
||||
array: assertArray,
|
||||
arrayBuffer: assertArrayBuffer,
|
||||
|
|
@ -986,6 +1231,7 @@ export const assert: Assert = {
|
|||
error: assertError,
|
||||
evenInteger: assertEvenInteger,
|
||||
falsy: assertFalsy,
|
||||
finiteNumber: assertFiniteNumber,
|
||||
float32Array: assertFloat32Array,
|
||||
float64Array: assertFloat64Array,
|
||||
formData: assertFormData,
|
||||
|
|
@ -1003,6 +1249,7 @@ export const assert: Assert = {
|
|||
map: assertMap,
|
||||
nan: assertNan,
|
||||
nativePromise: assertNativePromise,
|
||||
negativeInteger: assertNegativeInteger,
|
||||
negativeNumber: assertNegativeNumber,
|
||||
nodeStream: assertNodeStream,
|
||||
nonEmptyArray: assertNonEmptyArray,
|
||||
|
|
@ -1011,6 +1258,8 @@ export const assert: Assert = {
|
|||
nonEmptySet: assertNonEmptySet,
|
||||
nonEmptyString: assertNonEmptyString,
|
||||
nonEmptyStringAndNotWhitespace: assertNonEmptyStringAndNotWhitespace,
|
||||
nonNegativeInteger: assertNonNegativeInteger,
|
||||
nonNegativeNumber: assertNonNegativeNumber,
|
||||
null: assertNull,
|
||||
nullOrUndefined: assertNullOrUndefined,
|
||||
number: assertNumber,
|
||||
|
|
@ -1019,6 +1268,7 @@ export const assert: Assert = {
|
|||
observable: assertObservable,
|
||||
oddInteger: assertOddInteger,
|
||||
plainObject: assertPlainObject,
|
||||
positiveInteger: assertPositiveInteger,
|
||||
positiveNumber: assertPositiveNumber,
|
||||
primitive: assertPrimitive,
|
||||
promise: assertPromise,
|
||||
|
|
@ -1061,7 +1311,7 @@ const methodTypeMap = {
|
|||
isBigUint64Array: 'BigUint64Array',
|
||||
isBlob: 'Blob',
|
||||
isBoolean: 'boolean',
|
||||
isBoundFunction: 'Function',
|
||||
isBoundFunction: 'bound Function',
|
||||
isBuffer: 'Buffer',
|
||||
isClass: 'Class',
|
||||
isDataView: 'DataView',
|
||||
|
|
@ -1077,6 +1327,7 @@ const methodTypeMap = {
|
|||
isError: 'Error',
|
||||
isEvenInteger: 'even integer',
|
||||
isFalsy: 'falsy',
|
||||
isFiniteNumber: 'finite number',
|
||||
isFloat32Array: 'Float32Array',
|
||||
isFloat64Array: 'Float64Array',
|
||||
isFormData: 'FormData',
|
||||
|
|
@ -1094,6 +1345,7 @@ const methodTypeMap = {
|
|||
isMap: 'Map',
|
||||
isNan: 'NaN',
|
||||
isNativePromise: 'native Promise',
|
||||
isNegativeInteger: 'negative integer',
|
||||
isNegativeNumber: 'negative number',
|
||||
isNodeStream: 'Node.js Stream',
|
||||
isNonEmptyArray: 'non-empty array',
|
||||
|
|
@ -1102,6 +1354,8 @@ const methodTypeMap = {
|
|||
isNonEmptySet: 'non-empty set',
|
||||
isNonEmptyString: 'non-empty string',
|
||||
isNonEmptyStringAndNotWhitespace: 'non-empty string and not whitespace',
|
||||
isNonNegativeInteger: 'non-negative integer',
|
||||
isNonNegativeNumber: 'non-negative number',
|
||||
isNull: 'null',
|
||||
isNullOrUndefined: 'null or undefined',
|
||||
isNumber: 'number',
|
||||
|
|
@ -1110,12 +1364,13 @@ const methodTypeMap = {
|
|||
isObservable: 'Observable',
|
||||
isOddInteger: 'odd integer',
|
||||
isPlainObject: 'plain object',
|
||||
isPositiveInteger: 'positive integer',
|
||||
isPositiveNumber: 'positive number',
|
||||
isPrimitive: 'primitive',
|
||||
isPromise: 'Promise',
|
||||
isPropertyKey: 'PropertyKey',
|
||||
isRegExp: 'RegExp',
|
||||
isSafeInteger: 'integer',
|
||||
isSafeInteger: 'safe integer',
|
||||
isSet: 'Set',
|
||||
isSharedArrayBuffer: 'SharedArrayBuffer',
|
||||
isString: 'string',
|
||||
|
|
@ -1146,17 +1401,26 @@ function isIsMethodName(value: unknown): value is IsMethodName {
|
|||
return isMethodNames.includes(value as IsMethodName);
|
||||
}
|
||||
|
||||
export function assertAll(predicate: Predicate, ...values: unknown[]): void | never {
|
||||
export function assertAll(predicate: Predicate | readonly Predicate[], ...values: unknown[]): void | never {
|
||||
if (values.length === 0) {
|
||||
throw new TypeError('Invalid number of values');
|
||||
}
|
||||
|
||||
if (!isAll(predicate, ...values)) {
|
||||
const expectedType = isIsMethodName(predicate.name) ? methodTypeMap[predicate.name] : 'predicate returns truthy for all values';
|
||||
const predicateFunction = predicate as Predicate;
|
||||
const expectedType = !Array.isArray(predicate) && isIsMethodName(predicateFunction.name) ? methodTypeMap[predicateFunction.name] : 'predicate returns truthy for all values';
|
||||
throw new TypeError(typeErrorMessageMultipleValues(expectedType, values));
|
||||
}
|
||||
}
|
||||
|
||||
export function assertAny(predicate: Predicate | Predicate[], ...values: unknown[]): void | never {
|
||||
export function assertAny(predicate: Predicate | readonly Predicate[], ...values: unknown[]): void | never {
|
||||
if (values.length === 0) {
|
||||
throw new TypeError('Invalid number of values');
|
||||
}
|
||||
|
||||
if (!isAny(predicate, ...values)) {
|
||||
const predicates = isArray(predicate) ? predicate : [predicate];
|
||||
const expectedTypes = predicates.map(predicate => isIsMethodName(predicate.name) ? methodTypeMap[predicate.name] : 'predicate returns truthy for any value');
|
||||
const predicates = Array.isArray(predicate) ? predicate as readonly Predicate[] : [predicate as Predicate];
|
||||
const expectedTypes = predicates.map(singlePredicate => isIsMethodName(singlePredicate.name) ? methodTypeMap[singlePredicate.name] : 'predicate returns truthy for any value');
|
||||
throw new TypeError(typeErrorMessageMultipleValues(expectedTypes, values));
|
||||
}
|
||||
}
|
||||
|
|
@ -1192,7 +1456,7 @@ export function assertArrayLike<T = unknown>(value: unknown, message?: string):
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
export function assertAsyncFunction(value: unknown, message?: string): asserts value is Function {
|
||||
if (!isAsyncFunction(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value));
|
||||
|
|
@ -1247,10 +1511,10 @@ export function assertBoolean(value: unknown, message?: string): asserts value i
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
export function assertBoundFunction(value: unknown, message?: string): asserts value is Function {
|
||||
if (!isBoundFunction(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('Function', value));
|
||||
throw new TypeError(message ?? typeErrorMessage('bound Function', value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1347,6 +1611,12 @@ export function assertFalsy(value: unknown, message?: string): asserts value is
|
|||
}
|
||||
}
|
||||
|
||||
export function assertFiniteNumber(value: unknown, message?: string): asserts value is number {
|
||||
if (!isFiniteNumber(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('finite number', value));
|
||||
}
|
||||
}
|
||||
|
||||
export function assertFloat32Array(value: unknown, message?: string): asserts value is Float32Array {
|
||||
if (!isFloat32Array(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('Float32Array', value));
|
||||
|
|
@ -1365,7 +1635,7 @@ export function assertFormData(value: unknown, message?: string): asserts value
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
export function assertFunction(value: unknown, message?: string): asserts value is Function {
|
||||
if (!isFunction(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('Function', value));
|
||||
|
|
@ -1450,6 +1720,12 @@ 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 {
|
||||
if (!isNegativeNumber(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('negative number', value));
|
||||
|
|
@ -1498,14 +1774,26 @@ export function assertNonEmptyStringAndNotWhitespace(value: unknown, message?: s
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function assertNonNegativeInteger(value: unknown, message?: string): asserts value is number {
|
||||
if (!isNonNegativeInteger(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('non-negative integer', value));
|
||||
}
|
||||
}
|
||||
|
||||
export function assertNonNegativeNumber(value: unknown, message?: string): asserts value is number {
|
||||
if (!isNonNegativeNumber(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('non-negative number', value));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function assertNull(value: unknown, message?: string): asserts value is null {
|
||||
if (!isNull(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('null', value));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function assertNullOrUndefined(value: unknown, message?: string): asserts value is null | undefined {
|
||||
if (!isNullOrUndefined(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('null or undefined', value));
|
||||
|
|
@ -1524,7 +1812,7 @@ export function assertNumericString(value: unknown, message?: string): asserts v
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function assertObject(value: unknown, message?: string): asserts value is object {
|
||||
if (!isObject(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('Object', value));
|
||||
|
|
@ -1549,6 +1837,12 @@ 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 {
|
||||
if (!isPositiveNumber(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('positive number', value));
|
||||
|
|
@ -1567,7 +1861,7 @@ export function assertPromise<T = unknown>(value: unknown, message?: string): as
|
|||
}
|
||||
}
|
||||
|
||||
export function assertPropertyKey(value: unknown, message?: string): asserts value is number {
|
||||
export function assertPropertyKey(value: unknown, message?: string): asserts value is PropertyKey {
|
||||
if (!isPropertyKey(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('PropertyKey', value));
|
||||
}
|
||||
|
|
@ -1581,7 +1875,7 @@ export function assertRegExp(value: unknown, message?: string): asserts value is
|
|||
|
||||
export function assertSafeInteger(value: unknown, message?: string): asserts value is number {
|
||||
if (!isSafeInteger(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('integer', value));
|
||||
throw new TypeError(message ?? typeErrorMessage('safe integer', value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1688,21 +1982,21 @@ export function assertValidLength(value: unknown, message?: string): asserts val
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function assertWeakMap<Key extends object = object, Value = unknown>(value: unknown, message?: string): asserts value is WeakMap<Key, Value> {
|
||||
if (!isWeakMap(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('WeakMap', value));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function assertWeakRef<T extends object = object>(value: unknown, message?: string): asserts value is WeakRef<T> {
|
||||
if (!isWeakRef(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('WeakRef', value));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function assertWeakSet<T extends object = object>(value: unknown, message?: string): asserts value is WeakSet<T> {
|
||||
if (!isWeakSet(value)) {
|
||||
throw new TypeError(message ?? typeErrorMessage('WeakSet', value));
|
||||
|
|
@ -1720,10 +2014,25 @@ export default is;
|
|||
export type {
|
||||
ArrayLike,
|
||||
Class,
|
||||
EvenInteger,
|
||||
FiniteNumber,
|
||||
Integer,
|
||||
NaN,
|
||||
NegativeInfinity,
|
||||
NegativeInteger,
|
||||
NegativeNumber,
|
||||
NodeStream,
|
||||
NonNegativeInteger,
|
||||
NonNegativeNumber,
|
||||
ObservableLike,
|
||||
OddInteger,
|
||||
PositiveInfinity,
|
||||
PositiveInteger,
|
||||
PositiveNumber,
|
||||
Predicate,
|
||||
Primitive,
|
||||
SafeInteger,
|
||||
TypedArray,
|
||||
UrlString,
|
||||
} from './types.js';
|
||||
ValidLength,
|
||||
} from './types.ts';
|
||||
|
|
|
|||
121
source/types.ts
121
source/types.ts
|
|
@ -4,7 +4,8 @@
|
|||
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
||||
*/
|
||||
export type Primitive =
|
||||
| null // eslint-disable-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
| null
|
||||
| undefined
|
||||
| string
|
||||
| number
|
||||
|
|
@ -53,10 +54,11 @@ export type ObservableLike = {
|
|||
[Symbol.observable](): ObservableLike;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export type Falsy = false | 0 | 0n | '' | null | undefined;
|
||||
|
||||
export type WeakRef<T extends object> = { // eslint-disable-line @typescript-eslint/ban-types, unicorn/prevent-abbreviations
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export type WeakRef<T extends object> = {
|
||||
readonly [Symbol.toStringTag]: 'WeakRef';
|
||||
deref(): T | undefined;
|
||||
};
|
||||
|
|
@ -76,9 +78,122 @@ export type NonEmptyString = string & {0: string};
|
|||
|
||||
export type Whitespace = ' ';
|
||||
|
||||
type Brand<Key extends string> = Readonly<Record<Key, true>>;
|
||||
|
||||
/**
|
||||
A string that represents a valid URL.
|
||||
|
||||
This is a branded type to prevent incorrect TypeScript type narrowing.
|
||||
*/
|
||||
export type UrlString = string & {readonly __brand: 'UrlString'};
|
||||
|
||||
// Keep numeric guards branded and simple. This intentionally favors correct false-branch narrowing for `number` inputs over perfect success-branch narrowing for numeric literal unions.
|
||||
|
||||
/**
|
||||
The IEEE 754 "Not-a-Number" value, typed as a subtype of `number`.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type NaN = number & Brand<'__nanBrand'>;
|
||||
|
||||
/**
|
||||
A finite number (excludes `NaN`, `Infinity`, and `-Infinity`).
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type FiniteNumber = number & Brand<'__finiteNumberBrand'>;
|
||||
|
||||
/**
|
||||
A number greater than or equal to zero.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type NonNegativeNumber = number & Brand<'__nonNegativeNumberBrand'>;
|
||||
|
||||
/**
|
||||
An integer value (no fractional part).
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type Integer = FiniteNumber & Brand<'__integerBrand'>;
|
||||
|
||||
/**
|
||||
A number greater than zero.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type PositiveNumber = NonNegativeNumber & Brand<'__positiveNumberBrand'>;
|
||||
|
||||
/**
|
||||
A number less than zero.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type NegativeNumber = number & Brand<'__negativeNumberBrand'>;
|
||||
|
||||
/**
|
||||
An integer less than zero.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type NegativeInteger = Integer & NegativeNumber & Brand<'__negativeIntegerBrand'>;
|
||||
|
||||
/**
|
||||
An integer greater than or equal to zero.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type NonNegativeInteger = Integer & NonNegativeNumber & Brand<'__nonNegativeIntegerBrand'>;
|
||||
|
||||
/**
|
||||
An integer greater than zero.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type PositiveInteger = NonNegativeInteger & PositiveNumber & Brand<'__positiveIntegerBrand'>;
|
||||
|
||||
// Note: type-fest uses the `1e999` overflow trick to represent these types (since TypeScript has
|
||||
// no built-in Infinity type), but we use branded types here for consistency and to avoid
|
||||
// relying on numeric overflow behavior.
|
||||
|
||||
/**
|
||||
A positive infinite number (`Infinity`).
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type PositiveInfinity = PositiveNumber & Brand<'__positiveInfinityBrand'>;
|
||||
|
||||
/**
|
||||
A negative infinite number (`-Infinity`).
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type NegativeInfinity = NegativeNumber & Brand<'__negativeInfinityBrand'>;
|
||||
|
||||
/**
|
||||
A safe integer (within the range of `Number.MIN_SAFE_INTEGER` to `Number.MAX_SAFE_INTEGER`).
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type SafeInteger = Integer & Brand<'__safeIntegerBrand'>;
|
||||
|
||||
/**
|
||||
An even integer.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type EvenInteger = Integer & Brand<'__evenIntegerBrand'>;
|
||||
|
||||
/**
|
||||
An odd integer.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type OddInteger = Integer & Brand<'__oddIntegerBrand'>;
|
||||
|
||||
/**
|
||||
A non-negative safe integer, suitable as an array or string length.
|
||||
|
||||
Branded to prevent false-branch narrowing to `never` when the input is `number`.
|
||||
*/
|
||||
export type ValidLength = SafeInteger & NonNegativeInteger & Brand<'__validLengthBrand'>;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export function keysOf<T extends Record<PropertyKey, unknown>>(value: T): Array<keyof T> {
|
||||
return Object.keys(value) as Array<keyof T>;
|
||||
return Object.keys(value) as Array<keyof T>; // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
}
|
||||
|
|
|
|||
2562
test/test.ts
2562
test/test.ts
File diff suppressed because it is too large
Load diff
12
test/tsconfig.json
Normal file
12
test/tsconfig.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "..",
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false
|
||||
},
|
||||
"include": [
|
||||
"../source",
|
||||
"type-tests.ts"
|
||||
]
|
||||
}
|
||||
405
test/type-tests.ts
Normal file
405
test/type-tests.ts
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
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,5 +1,11 @@
|
|||
{
|
||||
"extends": "@sindresorhus/tsconfig",
|
||||
"compilerOptions": {
|
||||
"types": ["node"],
|
||||
"rootDir": "source",
|
||||
"allowImportingTsExtensions": true,
|
||||
"rewriteRelativeImportExtensions": true
|
||||
},
|
||||
"include": [
|
||||
"source"
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue