# @wistia/type-guards — full reference

Runtime type guards and utility types for TypeScript. Every guard is a
`value is T` predicate that narrows `unknown` values; every type is a
small composable building block. Side-effect free, tree-shakeable, ESM
and CJS builds.

## Install

```sh
npm install @wistia/type-guards
yarn add @wistia/type-guards
pnpm add @wistia/type-guards
```

## Import

```ts
import {
  isString,
  isNotNil,
  isNonEmptyArray,
  type Nilable,
  type NonEmptyArray,
} from '@wistia/type-guards';
```

## Guards

<!-- AUTOGEN:LLMS-FULL-GUARDS:START -->
### `hasKey`

```ts
hasKey<Key extends string, Value>(value: unknown, key: Key): value is Record<Key, Value>
```

```ts
hasKey({ a: 1 }, 'a'); // true
hasKey({ a: 1 }, 'b'); // false
```

### `isArray`

```ts
isArray(value: unknown): value is unknown[]
```

```ts
isArray([1, 2]); // true
isArray('abc');  // false
```

### `isAsyncFunction`

```ts
isAsyncFunction(value: unknown): value is (...args: unknown[]) => Promise<unknown>
```

Detection relies on `constructor.name === 'AsyncFunction'` and is a
heuristic: async functions transpiled to regular functions return false,
async generator functions return false, and a forged `constructor`
property can fool the check. Bound async functions return true, since
`bind` preserves the prototype chain. Synchronous functions that return
promises also return false.

```ts
isAsyncFunction(async () => {}); // true
isAsyncFunction(() => {});       // false
```

### `isBigInt`

```ts
isBigInt(value: unknown): value is bigint
```

```ts
isBigInt(10n); // true
isBigInt(10);  // false
```

### `isBoolean`

```ts
isBoolean(value: unknown): value is boolean
```

```ts
isBoolean(true); // true
isBoolean(1);    // false
```

### `isDate`

```ts
isDate(value: unknown): value is Date
```

Matches `Date` instances only. Does not parse date strings or
accept numeric timestamps.

```ts
isDate(new Date());   // true
isDate('2024-01-01'); // false
```

### `isEmptyArray`

```ts
isEmptyArray(value: unknown): value is never[]
```

```ts
isEmptyArray([]);  // true
isEmptyArray([1]); // false
```

### `isEmptyRecord`

```ts
isEmptyRecord(value: unknown): value is EmptyObject
```

```ts
isEmptyRecord({});       // true
isEmptyRecord({ a: 1 }); // false
```

### `isEmptyString`

```ts
isEmptyString(value: unknown): value is ''
```

```ts
isEmptyString('');  // true
isEmptyString('a'); // false
```

### `isError`

```ts
isError(value: unknown): value is Error
```

Matches subclasses of `Error` too (e.g. `TypeError`, custom errors).

```ts
isError(new Error('boom')); // true
isError('boom');            // false
```

### `isFalsy`

```ts
isFalsy(value: unknown): value is Falsy
```

Returns true for `false`, `0`, `-0`, `0n`, `''`, `null`, `undefined`,
and `NaN`.

```ts
isFalsy(0); // true
isFalsy(1); // false
```

### `isFiniteNumber`

```ts
isFiniteNumber(value: unknown): value is number
```

```ts
isFiniteNumber(42);       // true
isFiniteNumber(Infinity); // false
```

### `isFunction`

```ts
isFunction(value: unknown): value is (...args: unknown[]) => unknown
```

```ts
isFunction(() => {}); // true
isFunction({});       // false
```

### `isHtmlButtonElement`

```ts
isHtmlButtonElement(value: unknown): value is HTMLButtonElement
```

```ts
isHtmlButtonElement(document.createElement('button')); // true
isHtmlButtonElement(document.createElement('div'));    // false
```

### `isHtmlElement`

```ts
isHtmlElement(value: unknown): value is HTMLElement
```

```ts
isHtmlElement(document.body); // true
isHtmlElement('div');         // false
```

### `isHtmlInputElement`

```ts
isHtmlInputElement(value: unknown): value is HTMLInputElement
```

```ts
isHtmlInputElement(document.createElement('input')); // true
isHtmlInputElement(document.createElement('div'));   // false
```

### `isHtmlVideoElement`

```ts
isHtmlVideoElement(value: unknown): value is HTMLVideoElement
```

```ts
isHtmlVideoElement(document.createElement('video')); // true
isHtmlVideoElement(document.createElement('div'));   // false
```

### `isInteger`

```ts
isInteger(value: unknown): value is number
```

Uses `Number.isInteger`, so non-finite values (`NaN`, `Infinity`)
return false.

```ts
isInteger(5);   // true
isInteger(5.5); // false
```

### `isIterable`

```ts
isIterable(value: unknown): value is Iterable<unknown>
```

Strings are iterable and return true. Plain objects without
`Symbol.iterator` return false.

```ts
isIterable([1, 2, 3]); // true
isIterable({});        // false
```

### `isMap`

```ts
isMap(value: unknown): value is Map<unknown, unknown>
```

WeakMap instances return false.

```ts
isMap(new Map()); // true
isMap({});        // false
```

### `isMouseEvent`

```ts
isMouseEvent(value: unknown): value is MouseEvent
```

```ts
isMouseEvent(new MouseEvent('click')); // true
isMouseEvent(new Event('change'));     // false
```

### `isNaN`

```ts
isNaN(value: unknown): value is number
```

Uses `Number.isNaN` (not the coercive global `isNaN`), so only the
literal `NaN` value returns true.

```ts
isNaN(Number.NaN); // true
isNaN(0);          // false
```

### `isNil`

```ts
isNil(value: unknown): value is Nil
```

```ts
isNil(null); // true
isNil(0);    // false
```

### `isNonBlankString`

```ts
isNonBlankString(value: unknown): value is string
```

```ts
isNonBlankString('a');   // true
isNonBlankString('   '); // false
```

### `isNonEmptyArray`

```ts
isNonEmptyArray<T>(value: Nilable<T[] | UnknownRecord>): value is NonEmptyArray<T>
```

```ts
isNonEmptyArray([1]); // true
isNonEmptyArray([]);  // false
```

### `isNonEmptyRecord`

```ts
isNonEmptyRecord(value: unknown): value is Record<string, unknown>
```

```ts
isNonEmptyRecord({ a: 1 }); // true
isNonEmptyRecord({});       // false
```

### `isNonEmptyString`

```ts
isNonEmptyString(value: unknown): value is string
```

```ts
isNonEmptyString('a'); // true
isNonEmptyString('');  // false
```

### `isNonNaNNumber`

```ts
isNonNaNNumber(value: unknown): value is number
```

```ts
isNonNaNNumber(42);         // true
isNonNaNNumber(Number.NaN); // false
```

### `isNotArray`

```ts
isNotArray(value: unknown): value is Exclude<unknown, unknown[]>
```

```ts
isNotArray('x'); // true
isNotArray([]);  // false
```

### `isNotBoolean`

```ts
isNotBoolean(value: unknown): value is Exclude<unknown, boolean>
```

```ts
isNotBoolean(1);    // true
isNotBoolean(true); // false
```

### `isNotFunction`

```ts
isNotFunction(value: unknown): value is Exclude<unknown, (...args: unknown[]) => unknown>
```

```ts
isNotFunction(1);        // true
isNotFunction(() => {}); // false
```

### `isNotNil`

```ts
isNotNil<T>(value: Nil | T): value is T
```

Common in `.filter(isNotNil)` to drop `null`/`undefined` from arrays
with narrowing.

```ts
isNotNil(0);    // true
isNotNil(null); // false

const items: (string | null)[] = ['a', null, 'b'];
const clean: string[] = items.filter(isNotNil); // ['a', 'b']
```

### `isNotNull`

```ts
isNotNull<T>(value: unknown): value is Exclude<T, null>
```

```ts
isNotNull(undefined); // true
isNotNull(null);      // false
```

### `isNotNumber`

```ts
isNotNumber(value: unknown): value is Exclude<unknown, number>
```

```ts
isNotNumber('1'); // true
isNotNumber(1);   // false
```

### `isNotRecord`

```ts
isNotRecord(value: unknown): value is Exclude<unknown, EmptyObject | Record<string, unknown>>
```

```ts
isNotRecord([]); // true
isNotRecord({}); // false
```

### `isNotString`

```ts
isNotString(value: unknown): value is Exclude<unknown, string>
```

```ts
isNotString(1);   // true
isNotString('a'); // false
```

### `isNotUndefined`

```ts
isNotUndefined<T>(value: Undefinable<T>): value is Exclude<T, undefined>
```

```ts
isNotUndefined(null);      // true
isNotUndefined(undefined); // false
```

### `isNotVoid`

```ts
isNotVoid(value: unknown): value is Exclude<unknown, void>
```

```ts
isNotVoid(0);         // true
isNotVoid(undefined); // false
```

### `isNull`

```ts
isNull(value: unknown): value is null
```

```ts
isNull(null);      // true
isNull(undefined); // false
```

### `isNumber`

```ts
isNumber(value: unknown): value is number
```

`NaN` is a `number`, so `isNumber(NaN)` is true. Use `isInteger` or
combine with `!isNaN(value)` if you need a finite number.

```ts
isNumber(1);   // true
isNumber('1'); // false
```

### `isPlainObject`

```ts
isPlainObject(value: unknown): value is Record<string, unknown>
```

```ts
isPlainObject({});         // true
isPlainObject(new Date()); // false
```

### `isPromise`

```ts
isPromise(value: unknown): value is Promise<unknown>
```

The full `Promise` method surface is required so the narrowed type is
accurate: `then`, `catch`, and `finally` must all be functions. Thenables
that only implement a subset are rejected.

```ts
isPromise(Promise.resolve()); // true
isPromise({ then: () => 1 }); // false
```

### `isRecord`

```ts
isRecord(value: unknown): value is EmptyObject | Record<string, unknown>
```

```ts
isRecord({}); // true
isRecord([]); // false
```

### `isRegExp`

```ts
isRegExp(value: unknown): value is RegExp
```

```ts
isRegExp(/abc/);   // true
isRegExp('/abc/'); // false
```

### `isSet`

```ts
isSet(value: unknown): value is Set<unknown>
```

WeakSet instances return false.

```ts
isSet(new Set()); // true
isSet([]);        // false
```

### `isString`

```ts
isString(value: unknown): value is string
```

```ts
isString('hi'); // true
isString(42);   // false
```

### `isSvgElement`

```ts
isSvgElement(value: unknown): value is SVGElement
```

```ts
isSvgElement(document.createElementNS('http://www.w3.org/2000/svg', 'svg')); // true
isSvgElement(document.createElement('div'));                                // false
```

### `isSymbol`

```ts
isSymbol(value: unknown): value is symbol
```

```ts
isSymbol(Symbol('a')); // true
isSymbol('symbol');    // false
```

### `isTextNode`

```ts
isTextNode(value: unknown): value is Text
```

```ts
isTextNode(document.createTextNode('hi')); // true
isTextNode(document.createElement('div')); // false
```

### `isTruthy`

```ts
isTruthy(value: unknown): boolean
```

The complement of `isFalsy`. Does not provide narrowing on its own;
use `isNotNil` or a specific positive guard when narrowing matters.

```ts
isTruthy(1); // true
isTruthy(0); // false
```

### `isUndefined`

```ts
isUndefined(value: unknown): value is undefined
```

```ts
isUndefined(undefined); // true
isUndefined(null);      // false
```

### `isVoid`

```ts
isVoid(value: unknown): value is void
```

```ts
isVoid(undefined); // true
isVoid(0);         // false
```

### `isWeakMap`

```ts
isWeakMap(value: unknown): value is WeakMap<WeakKey, unknown>
```

Map instances return false. Narrows to `WeakMap<WeakKey, unknown>`, since
weak collections accept non-registered symbols as keys (ES2023).

```ts
isWeakMap(new WeakMap()); // true
isWeakMap(new Map());     // false
```

### `isWeakSet`

```ts
isWeakSet(value: unknown): value is WeakSet<WeakKey>
```

Set instances return false. Narrows to `WeakSet<WeakKey>`, since weak
collections accept non-registered symbols as members (ES2023).

```ts
isWeakSet(new WeakSet()); // true
isWeakSet(new Set());     // false
```

### `readonlyArrayIncludes`

```ts
readonlyArrayIncludes<T>(arr: readonly T[], elem: unknown): elem is T
```

```ts
const arr = ['a', 'b'] as const;
readonlyArrayIncludes(arr, 'a'); // true
readonlyArrayIncludes(arr, 'z'); // false
```
<!-- AUTOGEN:LLMS-FULL-GUARDS:END -->

## Types

<!-- AUTOGEN:LLMS-FULL-TYPES:START -->
### `Arrayable<T>`

```ts
type Arrayable<T> = T | T[];
type Tags = Arrayable<string>; // string | string[]
```

### `Falsy`

```ts
type Falsy = typeof Number.NaN | '' | 0n | false | null | undefined;
type X = Falsy; // number | '' | 0n | false | null | undefined
```

### `NestedNonNullable<T, P extends Paths<T> & string>`

```ts
type NestedNonNullable<T, P extends Paths<T> & string> = NonNullable<Get<T, P>>;
type User = { profile?: { name?: string } };
type Name = NestedNonNullable<User, 'profile.name'>; // string
```

This type recursively traverses the object along the given path and applies `NonNullable` to the resulting type.
It may fail for excessively deep property paths or in the presence of circular references. In such cases, consider
using nested `NonNullable` definitions to avoid errors such as:
- TS2589: Type instantiation is excessively deep and possibly infinite.
- TS2615: Type of property 'XYZ' circularly references itself in mapped type.

### `Nil`

```ts
type Nil = null | undefined;
type X = Nil; // null | undefined
```

### `Nilable<A>`

```ts
type Nilable<A> = A | Nil;
type Maybe = Nilable<string>; // string | null | undefined
```

### `NilableArray<T>`

```ts
type NilableArray<T> = Nilable<Nilable<T>[]>;
type Items = NilableArray<string>; // (string | null | undefined)[] | null | undefined
```

### `NonEmptyArray<T>`

```ts
type NonEmptyArray<T> = [T, ...T[]];
type Ids = NonEmptyArray<number>; // [number, ...number[]]
```

### `NotNilable<A>`

```ts
type NotNilable<A> = Exclude<A, Nil>;
type X = NotNilable<string | null | undefined>; // string
```

### `Nullable<A>`

```ts
type Nullable<A> = A | null;
type X = Nullable<string>; // string | null
```

### `NullableProperties<T extends UnknownRecord>`

```ts
type NullableProperties<T extends UnknownRecord> = { [Key in keyof T]: Nullable<T[Key]> };
type User = { name: string; age: number };
type X = NullableProperties<User>; // { name: string | null; age: number | null }
```

### `Truthy<T>`

```ts
type Truthy<T> = Exclude<T, Falsy>;
type X = Truthy<string | 0 | null>; // string
```

### `Undefinable<A>`

```ts
type Undefinable<A> = A | undefined;
type X = Undefinable<string>; // string | undefined
```
<!-- AUTOGEN:LLMS-FULL-TYPES:END -->

## Patterns

Filter out nullish values from a list, with narrowing:

```ts
import { isNotNil } from '@wistia/type-guards';

const raw: (string | null | undefined)[] = ['a', null, 'b', undefined];
const clean: string[] = raw.filter(isNotNil); // ['a', 'b']
```

Narrow a parameter before using it:

```ts
import { isString, isNonEmptyArray } from '@wistia/type-guards';

function describe(value: unknown): string {
  if (isString(value)) return value.toUpperCase();
  if (isNonEmptyArray<unknown>(value)) return `${value.length} items`;
  return 'other';
}
```

Safely access an unknown object key:

```ts
import { hasKey } from '@wistia/type-guards';

function readName(value: unknown): string | undefined {
  if (hasKey<'name', string>(value, 'name') && typeof value.name === 'string') {
    return value.name;
  }
  return undefined;
}
```
