Skip to content

Commit

Permalink
Merge pull request #4 from Resetand/is-any-guard-and-static-types-tests
Browse files Browse the repository at this point in the history
Is any guard and static types tests
  • Loading branch information
Resetand authored Mar 3, 2024
2 parents e4be0d1 + 6dcc124 commit fd39a6c
Show file tree
Hide file tree
Showing 9 changed files with 595 additions and 327 deletions.
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,13 @@ isBoolean(42); // false

Check if value is an NaN value.

ℹ️ This method is based on `Number.isNaN` and is not the same as global isNaN which returns true for undefined and other non-number values
ℹ️ This method is based on `Number.isNaN` and is not the same as global isNaN which converts value to number before checking

```tsx
isNaN(NaN); // true
isNaN(2 + {}); // false
isNaN(2 + {}); // true
isNaN(42); // false
isNaN({}); // false
```

---
Expand Down Expand Up @@ -538,6 +540,39 @@ isEmptyArray([1, 2, 3]); // false
Allows to validate runtime values (objects) with given schema or guard

### `validate` function args

One of the use cases for `validate` is to validate runtime values with given schema or guard

```ts
type FunctionExample = {
(value: string): string;
(value: string, otherValue: number): string;
(value: string, otherValue: number[]): string;
};

const example: FunctionExample = (...args: unknown[]) => {
if (validate(args, tuple(isString))) {
const [value] = args; // [string]
}
if (validate(args, tuple(isString, isNumber))) {
const [value, otherValue] = args; // [string, number]
}
if (validate(args, tuple(isString, isArrayOf(isNumber)))) {
const [value, otherValue] = args; // [string, number[]]
}

// fallback
};

/**
* This hack is required to correct type inference
* Although typescript v5+ has `const` genetic modifier, that allows to infer such cases correctly
* most of the projects use older versions of typescript, and this feature is breaking declaration files
*/
const tuple = <T extends unknown[]>(...args: T) => args;
```

### Usage

#### Validate object with schema
Expand Down
25 changes: 25 additions & 0 deletions src/guards/isAny.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Returns true for any value.
* This is special case guard that originally was created to be used with `validate` function.
*
* @example
* // using with validate function
* if (validate(value, { someProp: isAny, someOtherProp: isString })) {
* value.someProp // type unknown
* }
*
* @example
* const obj = JSON.parse(value) as { a: number } | { b: string };
* if (validate(obj, { a: isAny })) {
* obj.a // type number
* }
*
* @example
* isAny(1); // -> true
* isAny(''); // -> true
* isAny(<WHATEVER>); // -> true
*/
export default function isAny(_value: unknown): _value is unknown {
return true;
}
18 changes: 15 additions & 3 deletions src/guards/isEmpty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,30 @@ import isNil from './isNil';
import isInstanceOf from './isInstanceOf';

type EmptyObject = Record<PropertyKey, never>;
type EmptyMap<TKey = unknown> = Map<TKey, never>;
type EmptySet = Set<never>;
type EmptyArray = [];
type EmptyString = '';
type AnyEmptyValue = EmptyArray | EmptyObject | EmptyString | EmptyMap | EmptySet | null | undefined;

type $ExtractEmptyArray<T> = T extends any[] ? [] : never;
type $ExtractEmptyArray<T> = T extends any[] ? EmptyArray : never;
type $ExtractEmptyObject<T> = T extends Record<PropertyKey, unknown> ? EmptyObject : never;
type $ExtractEmptyString<T> = T extends string ? '' : never;
type $ExtractEmptyString<T> = T extends string ? EmptyString : never;
type $ExtractEmptyNull<T> = T extends null ? null : never;
type $ExtractEmptyUndefined<T> = T extends undefined ? undefined : never;
type $ExtractEmptyMap<T> = T extends Map<infer TKey, unknown> ? EmptyMap<TKey> : never;
type $ExtractEmptySet<T> = T extends Set<unknown> ? EmptySet : never;
type $ExtractEmptyUnknownFallback<T> = unknown extends T ? AnyEmptyValue : never;

type $ExtractEmpty<T> =
| $ExtractEmptyArray<T>
| $ExtractEmptyObject<T>
| $ExtractEmptyString<T>
| $ExtractEmptyNull<T>
| $ExtractEmptyUndefined<T>;
| $ExtractEmptyUndefined<T>
| $ExtractEmptyMap<T>
| $ExtractEmptySet<T>
| $ExtractEmptyUnknownFallback<T>;

type $ExtractEmptyFor<T> = $ExtractEmpty<T> extends T ? $ExtractEmpty<T> : $ExtractEmpty<T> & T;

Expand Down
10 changes: 0 additions & 10 deletions src/guards/isHasProperty.ts

This file was deleted.

8 changes: 3 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import isDate from './guards/isDate';
import isEmpty from './guards/isEmpty';
import isError from './guards/isError';
import isFunction from './guards/isFunction';
import isHasProperty from './guards/isHasProperty';
import isHas from './guards/isHas';
import isHasIn from './guards/isHasIn';
import isInstanceOf from './guards/isInstanceOf';
Expand All @@ -30,6 +29,7 @@ import isPromiseLike from './guards/isPromiseLike';
import isRegExp from './guards/isRegExp';
import isSymbol from './guards/isSymbol';
import isFalsy from './guards/isFalsy';
import isAny from './guards/isAny';

import _isGuard, { IsGuard } from './_is-guard';

Expand Down Expand Up @@ -63,9 +63,7 @@ const _container = {
Empty: isEmpty,
Falsy: isFalsy,
InstanceOf: isInstanceOf,

/** @deprecated – use `Has` instead */
HasProperty: isHasProperty,
Any: isAny,
Has: isHas,
HasIn: isHasIn,

Expand Down Expand Up @@ -103,7 +101,6 @@ export {
isFunction,
isHas,
isHasIn,
isHasProperty,
isInstanceOf,
isIterable,
isNaN,
Expand All @@ -119,6 +116,7 @@ export {
isRegExp,
isString,
isSymbol,
isAny,

// public utils
$some,
Expand Down
1 change: 1 addition & 0 deletions src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const validate: ValidateGuard = validateFactory({ strict: false });

/**
* Validate value against schema
* In strict mode, extra properties for objects are not allowed
* @example
* import { isString, isNumber, validateStrict } from 'utility-guards';
*
Expand Down
Loading

0 comments on commit fd39a6c

Please sign in to comment.