@wistia/type-guards
v0.14.0
Published
Type guards
Downloads
362,128
Readme
type-guards
This library provides a set of type guards that help safely check and narrow down types at runtime, making it easier to handle data validation and type checking in a type-safe manner. It also ships a set of general-purpose utility functions and utility types.
Install
npm install @wistia/type-guardsyarn add @wistia/type-guardspnpm add @wistia/type-guardsUsage
Every guard is a value is T predicate, so TypeScript narrows the value inside the if block:
import { isNonEmptyString, isNotNil } from '@wistia/type-guards';
function greet(value: unknown): string {
if (isNonEmptyString(value)) {
return `Hello, ${value}`;
}
return 'Hello, stranger';
}
const names: (string | null | undefined)[] = ['Alice', null, 'Bob'];
const cleaned: string[] = names.filter(isNotNil); // ['Alice', 'Bob']Guards
Primitives
| Guard | Narrows to |
| ------------------------ | ------------------------------------------ |
| isAsyncFunction(value) | (...args: unknown[]) => Promise<unknown> |
| isBigInt(value) | bigint |
| isBoolean(value) | boolean |
| isDate(value) | Date |
| isError(value) | Error |
| isFiniteNumber(value) | number |
| isFunction(value) | (...args: unknown[]) => unknown |
| isInteger(value) | number |
| isIterable(value) | Iterable<unknown> |
| isMap(value) | Map<unknown, unknown> |
| isNaN(value) | number |
| isNil(value) | Nil |
| isNonNaNNumber(value) | number |
| isNull(value) | null |
| isNumber(value) | number |
| isPromise(value) | Promise<unknown> |
| isRegExp(value) | RegExp |
| isSet(value) | Set<unknown> |
| isString(value) | string |
| isSymbol(value) | symbol |
| isUndefined(value) | undefined |
| isVoid(value) | void |
| isWeakMap(value) | WeakMap<WeakKey, unknown> |
| isWeakSet(value) | WeakSet<WeakKey> |
Arrays
| Guard | Narrows to |
| ---------------------------------- | ------------------ |
| isArray(value) | unknown[] |
| isEmptyArray(value) | never[] |
| isNonEmptyArray(value) | NonEmptyArray<T> |
| readonlyArrayIncludes(arr, elem) | T |
Records (plain objects, not arrays)
| Guard | Narrows to |
| ------------------------- | ------------------------- |
| hasKey(value, key) | Record<Key, Value> |
| isEmptyRecord(value) | EmptyObject |
| isNonEmptyRecord(value) | Record<string, unknown> |
| isPlainObject(value) | Record<string, unknown> |
| isRecord(value) | Record<string, unknown> |
Strings
| Guard | Narrows to |
| ------------------------- | ---------- |
| isEmptyString(value) | '' |
| isNonBlankString(value) | string |
| isNonEmptyString(value) | string |
Truthy / falsy
| Guard | Narrows to |
| ----------------- | ---------- |
| isFalsy(value) | Falsy |
| isTruthy(value) | boolean |
Negated
The isNot* variants are useful as .filter predicates to drop the unwanted type:
| Guard | Narrows to |
| ----------------------- | --------------------------------------------------- |
| isNotArray(value) | Exclude<unknown, unknown[]> |
| isNotBoolean(value) | Exclude<unknown, boolean> |
| isNotFunction(value) | Exclude<unknown, (...args: unknown[]) => unknown> |
| isNotNil(value) | T |
| isNotNull(value) | Exclude<T, null> |
| isNotNumber(value) | Exclude<unknown, number> |
| isNotRecord(value) | Exclude<unknown, Record<string, unknown>> |
| isNotString(value) | Exclude<unknown, string> |
| isNotUndefined(value) | Exclude<T, undefined> |
| isNotVoid(value) | Exclude<unknown, void> |
DOM
| Guard | Narrows to |
| ---------------------------- | ------------------- |
| isHtmlButtonElement(value) | HTMLButtonElement |
| isHtmlElement(value) | HTMLElement |
| isHtmlInputElement(value) | HTMLInputElement |
| isHtmlVideoElement(value) | HTMLVideoElement |
| isMouseEvent(value) | MouseEvent |
| isSvgElement(value) | SVGElement |
| isTextNode(value) | Text |
Types
| Type | Resolves to |
| --------------------------------------------------- | ------------------------------------------------------------- |
| Arrayable<T> | T \| T[] |
| Falsy | typeof Number.NaN \| '' \| 0n \| false \| null \| undefined |
| NestedNonNullable<T, P extends Paths<T> & string> | NonNullable<Get<T, P>> |
| Nil | null \| undefined |
| Nilable<A> | A \| Nil |
| NilableArray<T> | Nilable<Nilable<T>[]> |
| NonEmptyArray<T> | [T, ...T[]] |
| NotNilable<A> | Exclude<A, Nil> |
| Nullable<A> | A \| null |
| NullableProperties<T extends UnknownRecord> | { [Key in keyof T]: Nullable<T[Key]> } |
| Truthy<T> | Exclude<T, Falsy> |
| Undefinable<A> | A \| undefined |
Utilities
General-purpose helper functions that complement the guards. Unlike guards, these are not type predicates.
| Utility | Returns |
| ------------------------------------------------------------------------ | ------------------------------ |
| buildTimeDuration(numberOfMilliseconds) | TimeDuration |
| coerceToBoolean(value) | boolean |
| dateOnlyISOString(date, { timeZone = defaultTimeZone }) | string |
| dateOnlyString(date, { timeZone = defaultTimeZone, omitYear = false }) | string |
| dateOnlyStringForSentence(date, { timeZone = defaultTimeZone }) | string |
| dateOnlyStringNumeric(date, { timeZone = defaultTimeZone }) | string |
| dateTimeRounded(dateTime, toISOString = true) | string \| Date \| null |
| dateTimeString(date, { timeZone = defaultTimeZone, omitYear = false }) | string |
| dateTimeStringForSentence(date, { timeZone = defaultTimeZone }) | string |
| dateTimeToDate(dateTime) | Date \| null |
| dateTimeToISO(dateTime) | string \| null |
| dateToDateTime(date) | WistiaDateTimeObject \| null |
| dateUTCOffset(date) | string |
| dayOfWeekString(date, { timeZone = defaultTimeZone }) | string |
| getObjectEntries(obj) | [keyof T, T[keyof T]][] |
| getObjectKeys(obj) | (keyof T)[] |
| getObjectValues(obj) | T[keyof T][] |
| isUrl(value) | boolean |
| mediaDurationString(numberOfMilliseconds) | string |
| millisecondsToDurationISOString(numberOfMilliseconds) | string |
| monthDayStringNumeric(date, { timeZone = defaultTimeZone }) | string |
| parseDateString(str) | Date \| null |
| sessionDurationString(numberOfMilliseconds) | string |
| stripExtension(str) | string |
| timeAgoString(date, { nowAnchor = new Date(), includeTime = true }) | string |
| timeOnlyString(date, { timeZone = defaultTimeZone }) | string |
| tupleIncludes(tuple, item) | item is TTuple[number] |
Patterns
Filter nullish values from a list, with narrowing:
import { isNotNil } from '@wistia/type-guards';
const raw: (string | null | undefined)[] = ['a', null, 'b', undefined];
const clean: string[] = raw.filter(isNotNil); // ['a', 'b']Safely access a key on an unknown value:
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;
}Combine guards to handle a discriminated input:
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';
}Agent-friendly docs
Every export has a TSDoc @example block, so IDEs and LLM agents see usage at the call site via the bundled .d.ts. The package also ships llms.txt (compact index) and llms-full.txt (every signature plus an example) at the package root, following the llmstxt.org convention.
