@absoluteui/helpers/convert
Strict conversions that return undefined instead of NaN or Invalid Date.
import { ... } from '@absoluteui/helpers/convert';How to use
Section titled “How to use”Strict conversions for values that arrive as text or unknown: query strings, form fields, CSV cells, localStorage, and JSON from other systems. The to... functions return undefined for bad input instead of NaN or a guessed value; the ...OrThrow variants throw a ValidationError. The Helpers and services guide covers the shared conventions.
How do I read typed filters from a query string?
Section titled “How do I read typed filters from a query string?”coerceFields converts a whole record by a schema and returns a Result; all bad keys come back together in error.fields, ready for a form or a 400 response.
import { coerceFields } from '@absoluteui/helpers/convert';
const query = Object.fromEntries(new URLSearchParams('page=2&active=yes&hiredAfter=2025-01-01'));const parsed = coerceFields(query, { page: 'integer', active: 'boolean', hiredAfter: { kind: 'date', optional: true }, dept: { kind: 'string', optional: true },});parsed.ok ? [parsed.value.page, parsed.value.active, parsed.value.dept] : []; // => [2, true, undefined]const bad = coerceFields({ page: 'two', active: '' }, { page: 'integer', active: 'boolean' });bad.ok ? {} : bad.error.fields; // => { page: 'Expected integer.', active: 'Required.' }How do I parse numbers that users typed in their own format?
Section titled “How do I parse numbers that users typed in their own format?”Pass locale to accept that locale’s group and decimal separators. Text such as '12abc' or '' is rejected rather than half-parsed, unlike parseFloat.
import { toInteger, toNumber } from '@absoluteui/helpers/convert';
toNumber('1.234,5', { locale: 'de' }); // => 1234.5toNumber('1,234.5', { locale: 'en' }); // => 1234.5parseFloat('12abc'); // => 12toNumber('12abc'); // => undefinedtoInteger('7.5'); // => undefinedtoInteger('7.5', { rounding: 'half-even' }); // => 8How do I accept dates without guessing the format?
Section titled “How do I accept dates without guessing the format?”toDate accepts only a Date, epoch milliseconds, or ISO 8601 text; ambiguous forms like 01/02/2026 (January or February?) are rejected. A bare YYYY-MM-DD is UTC midnight. For calendar dates without a time, prefer helpers/date.
import { toDate, toDateOrThrow } from '@absoluteui/helpers/convert';
toDate('2026-10-05T09:00:00Z')?.toISOString(); // => '2026-10-05T09:00:00.000Z'toDate('01/02/2026'); // => undefinedtoDateOrThrow('next Friday'); // => throws HLP_CONVERT_DATEHow do I normalise a value that may be one item, many, or nothing?
Section titled “How do I normalise a value that may be one item, many, or nothing?”toArray and toSet accept a single value, any iterable, or null/undefined, which is handy for multi-select values and API fields that are sometimes a list. Strings are kept whole, not split into characters.
import { toArray, toSet } from '@absoluteui/helpers/convert';
toArray('HR'); // => ['HR']toArray(['HR', 'IT']); // => ['HR', 'IT']toArray(null); // => []toSet(['HR', 'IT', 'HR']).size; // => 2API reference
Section titled “API reference”Functions
Section titled “Functions”coerce
Converts value to the named kind with the strict to* rules; undefined on failure.
function coerce<K extends CoerceKind>(value: unknown, kind: K): CoerceTypes[K] | undefined;Example:
coerce('42', 'integer') // => 42coerceFields
Coerces a record (e.g. form or query values) by a schema. Missing, null and blank values fail
as required unless optional. Errors come back as one ValidationError (HLP_CONVERT_FIELDS)
whose fields maps each bad key to a message.
function coerceFields<S extends Readonly<Record<string, FieldSpec>>>(input: unknown, schema: S): Result<Coerced<S>, ValidationError>;Example:
coerceFields({ age: '42', active: 'yes' }, { age: 'integer', active: 'boolean' });// ok({ age: 42, active: true })parseIntStrict
Strict integer parse for radix 2-36: optional sign, digits only (no whitespace, prefixes or
trailing text); undefined when invalid or outside the safe-integer range.
function parseIntStrict(text: string, radix?: number): number | undefined;Example:
parseIntStrict('ff', 16) // => 255Example:
parseIntStrict('12px') // => undefinedtoArray
Array from anything: nullish -> [], arrays copied, iterables (Set, Map entries, generators) spread,
strings and other values wrapped ('ab' -> ['ab']).
function toArray<T>(value: Iterable<T> | T | null | undefined): T[];Example:
toArray(new Set([1, 2])) // => [1, 2]Example:
toArray(5) // => [5]toBigInt
Converts bigints, integer numbers and decimal integer strings (trimmed, up to 10,000 digits) to bigint.
function toBigInt(value: unknown): bigint | undefined;Example:
toBigInt('-12345678901234567890') // => -12345678901234567890ntoBoolean
Boolean conversion via parseBoolean (true/false/yes/no/y/n/on/off/1/0).
function toBoolean(value: unknown, options?: ParseBooleanOptions): boolean | undefined;Example:
toBoolean('off') // => falsetoDate
Strict date conversion: valid Date (copied), epoch milliseconds, or ISO 8601 text only -
YYYY-MM-DD (UTC midnight) or YYYY-MM-DDTHH:mm[:ss[.fff]] with optional Z/+/-HH:mm
(no zone = local time). Ambiguous forms like '01/02/2026' are rejected.
function toDate(value: unknown): Date | undefined;Example:
toDate('2026-09-29T10:00:00Z')?.getTime() // => 1790676000000Example:
toDate('01/02/2026') // => undefinedtoDateOrThrow
toDate or throw ValidationError (HLP_CONVERT_DATE).
function toDateOrThrow(value: unknown): Date;Example:
toDateOrThrow('2026-01-01')toInteger
Strict integer conversion with an explicit rounding mode.
function toInteger(value: unknown, options?: ToIntegerOptions): number | undefined;Example:
toInteger('42') // => 42Example:
toInteger('2.5', { rounding: 'half-even' }) // => 2Example:
toInteger(1.5) // => undefined // rounding 'none'toIntegerOrThrow
toInteger or throw ValidationError (HLP_CONVERT_INTEGER).
function toIntegerOrThrow(value: unknown, options?: ToIntegerOptions): number;Example:
toIntegerOrThrow('7') // => 7toMap
Map from a map (copied), an iterable of [key, value] pairs or a plain object; nullish -> empty map.
Returns undefined for anything else.
function toMap<K, V>(value: ReadonlyMap<K, V> | Iterable<readonly [K, V]>): Map<K, V> | undefined;function toMap<V>(value: Readonly<Record<string, V>>): Map<string, V> | undefined;function toMap(value: unknown): Map<unknown, unknown> | undefined;Example:
toMap({ a: 1 })?.get('a') // => 1toNumber
Strict number conversion. Accepts finite numbers, safe-range bigints and numeric strings
(trimmed; sign, decimals, exponent; - U+2212 as minus). Rejects '', whitespace, '12abc',
hex, NaN and +/-Infinity.
function toNumber(value: unknown, options?: ToNumberOptions): number | undefined;Example:
toNumber(' -1.5e3 ') // => -1500Example:
toNumber('1.234,5', { locale: 'de' }) // => 1234.5Example:
toNumber('12abc') // => undefinedtoNumberOrThrow
toNumber or throw ValidationError (HLP_CONVERT_NUMBER).
function toNumberOrThrow(value: unknown, options?: ToNumberOptions): number;Example:
toNumberOrThrow('3') // => 3toPlainObject
Plain object from a plain object (shallow copy), class instance (own enumerable props), Map
or iterable (including arrays) of [key, value] pairs with string/number keys. Unsafe keys (__proto__, …) from maps/pairs -> undefined.
function toPlainObject(value: unknown): Record<string, unknown> | undefined;Example:
toPlainObject(new Map([['a', 1]])) // => { a: 1 }toSafeInteger
Like toInteger but also requires Number.MIN_SAFE_INTEGER..MAX_SAFE_INTEGER.
function toSafeInteger(value: unknown, options?: ToIntegerOptions): number | undefined;Example:
toSafeInteger('9007199254740993') // => undefinedtoSet
Set from anything, with toArray rules (nullish -> empty set).
function toSet<T>(value: Iterable<T> | T | null | undefined): Set<T>;Example:
toSet([1, 1, 2]).size // => 2toStringSafe
Human-safe string for any value; never '[object Object]'. Nullish -> ''; dates -> ISO;
errors -> 'Name: message'; plain objects, arrays, maps and sets -> JSON (cycles as '[Circular]',
bigints as strings); objects with their own toString use it.
function toStringSafe(value: unknown): string;Example:
toStringSafe({ a: 1n }) // => '{"a":"1"}'Example:
toStringSafe(Symbol('x')) // => 'Symbol(x)'Interfaces
Section titled “Interfaces”CoerceTypes
Target types for coerce.
interface CoerceTypes { string: string; number: number; integer: number; 'safe-integer': number; bigint: bigint; boolean: boolean; date: Date; array: unknown[];}ToIntegerOptions
interface ToIntegerOptions extends ToNumberOptions { readonly rounding?: IntegerRounding;}ToNumberOptions
interface ToNumberOptions { readonly locale?: string;}Coerced
Result shape of coerceFields.
type Coerced<S extends Readonly<Record<string, FieldSpec>>> = { -readonly [P in keyof S]: S[P] extends { readonly optional: true; } ? CoerceTypes[SpecKind<S[P]>] | undefined : CoerceTypes[SpecKind<S[P]>];};CoerceKind
type CoerceKind = keyof CoerceTypes;FieldSpec
Field spec for coerceFields: a kind, or a kind with optional.
type FieldSpec = CoerceKind | { readonly kind: CoerceKind; readonly optional?: boolean;};IntegerRounding
How toInteger treats fractions. 'none' rejects them; 'round' rounds half away from zero.
type IntegerRounding = 'none' | 'trunc' | 'floor' | 'ceil' | 'round' | 'half-even';