Type guards
js
import { isDefined, isNumber, isObject, isString } from '@studiometa/js-toolkit/utils';Each one narrows the type.
Usage
ts
import { isDefined, isObject, isString } from '@studiometa/js-toolkit/utils';
function label(value: unknown): string {
if (isString(value)) return value; // string
if (isObject(value)) return JSON.stringify(value); // Record<string, unknown>
return '';
}
function first<T>(items: (T | undefined)[]): T[] {
return items.filter(isDefined); // T[]
}isDefined as a filter predicate is the case that earns the export: it is the one narrowing TypeScript will not do from a truthiness check.
The guards
isNull
ts
isNull(value: unknown): value is nullisDefined
ts
isDefined<T>(value: T | undefined): value is TNarrows T | undefined to T. Passing it by reference to filter is what it is for.
isString
ts
isString(value: unknown): value is stringisNumber
ts
isNumber(value: unknown): value is numberIt rejects NaN, because a NaN that passes a number check is a bug that surfaces three functions later.
isBoolean
ts
isBoolean(value: unknown): value is booleanisFunction
ts
isFunction(value: unknown): value is (...args: unknown[]) => unknownisObject
ts
isObject(value: unknown): value is Record<string, unknown>What is not here
| Not shipped | Write |
|---|---|
isArray | Array.isArray(value) |
isEmpty | the check the caller actually means |
isEmptyString | value === '' |
isDev | your bundler's own flag |
A guard earns its place by narrowing something the platform does not, or by being a predicate you pass by reference.