# @rickosborne/guard

Basic type guards building on helper types from  [@rickosborne/typical](https://www.npmjs.com/package/@rickosborne/typical).
## Usage

Install via your favorite package manager.

Each package supports CommonJS `require`, ESM `import`, and TypeScript usage.

You also have a choice: barrel imports or direct imports.

Barrel imports mean you're going to require/import everything from the same package-level namespace:

```typescript
// CommonJS
const { isPlainObject, isListOf } = require("@rickosborne/guard");
// ESM / TypeScript
import { isPlainObject, isListOf } from "@rickosborne/guard";
```

Implications:

- Nice and simple.
- Your build system needs to do tree-shaking well ... or you'll end up adding the entire package even if you only import two functions.

The other option is to use direct imports:

```typescript
// CommonJS
const { isPlainObject } = require("@rickosborne/guard/is-object");
const { isListOf } = require("@rickosborne/guard/is-list-of");
// ESM / TypeScript
import { isPlainObject } from "@rickosborne/guard/is-object.js";
import { isListOf } from "@rickosborne/guard/is-list-of.js";
```

Implications:

- You (probably) don't have to worry about tree-shaking as your build (likely) ends up with only the functions you need.

If you're using a modern build system, there aren't any strong reasons to prefer one way over the other.
It's really just down to your personal preference.

### A quick note about file extensions

Do you need to use file extensions?
And if so, which extensions?

Honestly ... this is a dumpster fire question.
It really comes down to your own setup and configuration.

Within each package itself:

- The CommonJS files all have `.cjs` extensions.
- The ESM files all have `.mjs` extensions.
- Node subpath exports have been set up to send `.js` imports to the `.cjs` (via `require`) or `.mjs` (via `import`) files, depending on your setup.

So, in theory, the only extension which _won't_ work would be `.ts` because the source isn't included.

If you run into a problem with a particular configuration, file a GitHub issue with:

- Your `tsconfig.json`'s `module`, `moduleResolution`, and `target` settings.
- Your `package.json`'s `type` and `imports` settings.
- An example of another package which imports correctly for you.

## License

This package is licensed as [CC-BY-NC-SA-4.0] unless otherwise noted.
That is, Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.

[CC-BY-NC-SA-4.0]: https://creativecommons.org/licenses/by-nc-sa/4.0/


***

## API

### Classes

#### ValidationError

<a id="api-validationerror"></a>

```typescript
 class ValidationError extends Error 
```

An error which collects any number of problems encountered while attempting to validate a value against a type schema/guard.


### Functions

#### assertDefined

<a id="api-assertdefined"></a>

```typescript
 function assertDefined<T>(value: T, messageOrError: MessageOrError): asserts value is NonNullable<T>;
```

Assert the given value is not null or undefined. Throws with the given message or error, otherwise.


#### assertInt

<a id="api-assertint"></a>

```typescript
 function assertInt(value: unknown, messageOrError: MessageOrError): asserts value is number;
```

Throw if the given value is not an integer.


#### assertJSONArray

<a id="api-assertjsonarray"></a>

```typescript
 function assertJSONArray(value: unknown): asserts value is JSONArray;
```

Assert the given value could be serialized as a JSON Array.


#### assertJSONObject

<a id="api-assertjsonobject"></a>

```typescript
 function assertJSONObject(value: unknown): asserts value is JSONObject;
```

Assert the given value could be serialized as a JSON Object.


#### assertJSONPrimitive

<a id="api-assertjsonprimitive"></a>

```typescript
 function assertJSONPrimitive(value: unknown): asserts value is JSONPrimitive;
```

Assert the given value could be serialized as a JSON Primitive.


#### assertJSONSerializable

<a id="api-assertjsonserializable"></a>

```typescript
 function assertJSONSerializable(value: unknown): asserts value is JSONSerializable;
```

Assert the given value could be serialized as JSON.


#### errorFromMessageOrError

<a id="api-errorfrommessageorerror"></a>

```typescript
errorFromMessageOrError: (messageOrError: MessageOrError, defaultConstructor?: (new (message: string) => Error)) => Error
```

Helper for guards which expect text or an error, or can generate one when needed.


#### expectDefined

<a id="api-expectdefined"></a>

```typescript
expectDefined: <T>(obj: T, messageOrError: MessageOrError) => NonNullable<T>
```

Coerce a value's type to exclude null or undefined, or throw if it actually is null or undefined.


#### expectInt

<a id="api-expectint"></a>

```typescript
expectInt: (obj: unknown, messageOrError: MessageOrError) => number
```

Coerce a value's type to a number, throwing if it's not an integer.


#### formatValidationProblem

<a id="api-formatvalidationproblem"></a>

```typescript
formatValidationProblem: (problem: ValidationProblem) => string
```

#### hasArray

<a id="api-hasarray"></a>

```typescript
 function hasArray<Name extends string>(obj: unknown, name: Name, predicate?: undefined): obj is {
    [K in Name]: unknown[];
};
```

Guard for whether the given value is an object which has a property with its own array value. This variant does not exhaustively check the items of the array.


#### hasArray

<a id="api-hasarray"></a>

```typescript
 function hasArray<Name extends string, Item>(obj: unknown, name: Name, predicate?: (item: unknown, index: number, items: unknown[]) => item is Item): obj is {
    [K in Name]: Item[];
};
```

Guard for whether the given value is an object which has a property with its own array value. This variant exhaustively checks the items of the array against the given predicate.


#### hasNumber

<a id="api-hasnumber"></a>

```typescript
hasNumber: <Name extends string>(obj: unknown, name: Name) => obj is { [k in Name]: number; }
```

Guard for whether an object has a property with the given name and a numeric value.


#### hasObject

<a id="api-hasobject"></a>

```typescript
hasObject: <Name extends string>(obj: unknown, name: Name) => obj is { [k in Name]: object; }
```

Guard for whether an object has a property with the given name and an object value.


#### hasOptional

<a id="api-hasoptional"></a>

```typescript
 function hasOptional<Name extends string>(obj: unknown, name: Name): obj is {
    [K in Name]?: unknown;
};
```

Guard for whether the given value is an object with an optional property with the given name. This variant does not check the value, only that the property exists.


#### hasOptional

<a id="api-hasoptional"></a>

```typescript
 function hasOptional<Name extends string, T>(obj: unknown, name: Name, predicate: (value: unknown) => value is T): obj is {
    [K in Name]?: T;
};
```

Guard for whether the given value is an object with an optional property with the given name. This variant checks the value against the given predicate.


#### hasOwn

<a id="api-hasown"></a>

```typescript
 function hasOwn<Name extends string | symbol>(obj: unknown, name: Name): obj is {
    [K in Name]: unknown;
};
```

Guard for whether the given value is an object with a property with the given name. This variant does not check the value, only that the property exists.


#### hasOwn

<a id="api-hasown"></a>

```typescript
 function hasOwn<Name extends string | symbol, T>(obj: unknown, name: Name, predicate: (value: unknown) => value is T): obj is {
    [K in Name]: T;
};
```

Guard for whether the given value is an object with a property with the given name. This variant checks the value against the given predicate.


#### hasPlainObject

<a id="api-hasplainobject"></a>

```typescript
hasPlainObject: <Name extends string>(obj: unknown, name: Name) => obj is { [k in Name]: Record<never, never>; }
```

Guard for whether an object has a property with the given name and a plain object value.


#### hasString

<a id="api-hasstring"></a>

```typescript
hasString: <Name extends string>(obj: unknown, name: Name) => obj is { [k in Name]: string; }
```

Check whether the given value is an object, has a property with the given name, and the value of that property is a string.


#### isAsyncIterableLike

<a id="api-isasynciterablelike"></a>

```typescript
isAsyncIterableLike: <T = unknown>(value: unknown) => value is AsyncIterable<T>
```

#### isDefined

<a id="api-isdefined"></a>

```typescript
isDefined: <T>(obj: T) => obj is NonNullable<T>
```

Guard to filter out null or undefined values.


#### isDigit

<a id="api-isdigit"></a>

```typescript
isDigit: (value: unknown) => value is Digit
```

#### isHexDigit

<a id="api-ishexdigit"></a>

```typescript
isHexDigit: (value: unknown) => value is HexDigit
```

#### isInt

<a id="api-isint"></a>

```typescript
isInt: (obj: unknown) => obj is number
```

Check whether the given value is not just numeric, but is also an integer.


#### isIterableLike

<a id="api-isiterablelike"></a>

```typescript
isIterableLike: <T = unknown>(value: unknown) => value is Iterable<T>
```

#### isIteratorLike

<a id="api-isiteratorlike"></a>

```typescript
isIteratorLike: <T = unknown>(value: unknown) => value is Iterator<T, unknown, unknown> | AsyncIterator<T, unknown, unknown>
```

#### isJSONArray

<a id="api-isjsonarray"></a>

```typescript
 function isJSONArray(value: unknown): value is JSONArray;
```

Type guard testing whether the value could be serialized as a JSON Array without losing information.


#### isJSONObject

<a id="api-isjsonobject"></a>

```typescript
 function isJSONObject(value: unknown): value is JSONObject;
```

Type guard for values which could be serialized as JSON Objects.


#### isJSONPrimitive

<a id="api-isjsonprimitive"></a>

```typescript
 function isJSONPrimitive(value: unknown): value is JSONPrimitive;
```

Type guard validating the value could be serialized as a JSON primitive.


#### isJSONSerializable

<a id="api-isjsonserializable"></a>

```typescript
 function isJSONSerializable(value: unknown): value is JSONSerializable;
```

Type guard for any value which could be serialized natively as JSON.


#### isListOf

<a id="api-islistof"></a>

```typescript
isListOf: <T>(list: unknown, predicate: (item: unknown, index: number, items: unknown[]) => item is T) => list is T[]
```

Guard to check if the given value is an array where all the items match the given predicate.


#### isObject

<a id="api-isobject"></a>

```typescript
isObject: (obj: unknown) => obj is NonNullable<object>
```

Guard to check that the given value is defined and object-like.


#### isPlainObject

<a id="api-isplainobject"></a>

```typescript
isPlainObject: (obj: unknown) => obj is Record<never, never>
```

Guard to check that the given value is defined, is an object, and seems to be a "plain" object, descending directly from Object. This won't prevent all shenanigans, but is a low-effort check.


#### isPromiseLike

<a id="api-ispromiselike"></a>

```typescript
isPromiseLike: <T = unknown>(value: unknown) => value is PromiseLike<T>
```

Type guard for a Promise-like "thenable".


#### isString

<a id="api-isstring"></a>

```typescript
isString: (value: unknown) => value is string
```

Type guard for a string value. Just calls `typeof`, but could make complicated type guard compositions easier to read.


#### isUnaryPredicate

<a id="api-isunarypredicate"></a>

```typescript
isUnaryPredicate: (obj: unknown) => obj is UnaryPredicate<unknown>
```

Tests whether the given object is a function and takes at least one parameter, and could maybe act as a unary predicate. Warning! Since no type information is available at runtime, it may not actually act as a predicate!


#### maybeInt

<a id="api-maybeint"></a>

```typescript
maybeInt: (text: string) => number | undefined
```

Convert to an integer, if it seems like it could be done safely. See [decimal separator on Wikipedia](https://en.wikipedia.org/wiki/Decimal_separator) for details on how this is probably very wrong in many countries.


#### scrubStackTrace

<a id="api-scrubstacktrace"></a>

```typescript
 function scrubStackTrace<E extends Error>(err: E, removeIf?: StackRemoveIf | undefined): E;
```

Wrap an Error in a proxy which cleans up the stack trace to be more human-readable. It filters out lines from third-party code, so you can quickly see your own code in the call stack. May optionally include some way of indicating additional lines which should be removed, so a guard function could make itself transparent, making it seem like the caller threw the error.



#### scrubStackTrace

<a id="api-scrubstacktrace"></a>

```typescript
 function scrubStackTrace(stack: string | undefined, removeIf?: StackRemoveIf | undefined): string | undefined;
```

#### validateJSONArray

<a id="api-validatejsonarray"></a>

```typescript
 function validateJSONArray(value: unknown, seen?: Map<unknown, ValidationProblem[]>, path?: string[]): ValidationProblem[];
```

Try to validate the given value's items could be serialized as a JSON Array without losing information. An empty result array implies the value is a valid JSON Array.


#### validateJSONObject

<a id="api-validatejsonobject"></a>

```typescript
 function validateJSONObject(value: unknown, seen?: Map<unknown, ValidationProblem[]>, path?: string[]): ValidationProblem[];
```

Try to validate the given value could be serialized as a JSON Object without losing information. An empty result array means the value is a valid JSON Object.


#### validateJSONPrimitive

<a id="api-validatejsonprimitive"></a>

```typescript
 function validateJSONPrimitive(value: unknown, path?: string[]): ValidationProblem[];
```

Try to validate the given value could be serialized as a JSON literal primitive without losing information. An empty result array implies the value is a valid JSON primitive.


#### validateJSONSerializable

<a id="api-validatejsonserializable"></a>

```typescript
 function validateJSONSerializable(value: unknown, seen?: Map<unknown, ValidationProblem[]>, path?: string[]): ValidationProblem[];
```

Try to validate that the given value could be serialized correctly as JSON without losing information. An empty result array implies the value is valid JSON.


### Interfaces

#### ThrowOnError

<a id="api-throwonerror"></a>

```typescript
export interface ThrowOnError 
```

Mixin added to function call options to indicate whether it should throw, or silently swallow the error.


#### ValidationErrorOptions

<a id="api-validationerroroptions"></a>

```typescript
export interface ValidationErrorOptions extends ErrorOptions 
```

#### ValidationProblem

<a id="api-validationproblem"></a>

```typescript
export interface ValidationProblem 
```

A problem encountered while attempting to validate a value against a type guard/schema.


### TypeAliases

#### Digit

<a id="api-digit"></a>

```typescript
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
```

#### HexDigit

<a id="api-hexdigit"></a>

```typescript
type HexDigit = Digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f";
```

#### MessageOrError

<a id="api-messageorerror"></a>

```typescript
type MessageOrError = string | Error | (() => (string | Error));
```

A message, an error, or something which can generate one of those.


#### StackRemoveIf

<a id="api-stackremoveif"></a>

```typescript
type StackRemoveIf = Predicate<string> | RegExp | string;
```

Specifier for which lines of a stack trace should be removed.


### Variables

#### NO_THROW

<a id="api-no-throw"></a>

```typescript
NO_THROW: Readonly<{
    readonly throwOnError: false;
}>
```

Value of [ThrowOnError](#api-throwonerror) which will avoid throwing.


#### notPlainObject

<a id="api-notplainobject"></a>

```typescript
notPlainObject: unique symbol
```

A symbol which can be exposed when you want [isPlainObject](#api-isplainobject) to be false for an object. It doesn't matter what the value is.


