@okyrychenko-dev/type-utils
v0.1.1
Published
Type-safe guards, assertions, and utility types for narrowing unknown values in TypeScript
Downloads
237
Maintainers
Readme
@okyrychenko-dev/type-utils
Type-safe guards, assertions, and utility types for narrowing
unknownvalues in TypeScript.
What This Library Does
type-utils gives you three composable layers:
- Guards —
is*functions that narrowunknownvalues with type predicates - Assertions —
assert*functions that narrow in place or throwTypeError/Error - Utility types — small type-level helpers for common value shapes and transformations
It has zero runtime dependencies and ships both ESM and CJS builds.
Features
- Runtime guards for primitives, collections, objects, functions, and built-ins
- Assertion functions and
assertNeverfor safe control-flow narrowing - Small composable utility types, including
Nullable,ValueOf, andNonEmptyArray - Type predicates and assertion signatures that preserve TypeScript narrowing
- Zero runtime dependencies and dual ESM/CJS builds
Installation
npm install @okyrychenko-dev/type-utils
# or
yarn add @okyrychenko-dev/type-utils
# or
pnpm add @okyrychenko-dev/type-utilsQuick Start
import { assertDefined, isString } from "@okyrychenko-dev/type-utils";
function greet(value: unknown): string {
if (isString(value)) {
return `Hello, ${value}!`;
}
return "Hello, stranger!";
}
function requireUser(user: User | null | undefined): User {
assertDefined(user, "User must be loaded before rendering.");
return user; // narrowed to `User`
}Guards
Primitives
import {
isBigInt,
isBoolean,
isDefined,
isFiniteNumber,
isNull,
isNullish,
isNumber,
isString,
isSymbol,
isUndefined,
} from "@okyrychenko-dev/type-utils";
isString("hi"); // true
isNumber(NaN); // true — use isFiniteNumber to exclude NaN/Infinity
isFiniteNumber(NaN); // false
isBoolean(true); // true
isBigInt(1n); // true
isSymbol(Symbol()); // true
isUndefined(undefined); // true
isNull(null); // true
isNullish(null); // true — null or undefined
isDefined(0); // true — anything except null/undefinedCollections
import {
isArray,
isMap,
isReadonlyArray,
isSet,
isWeakMap,
isWeakSet,
} from "@okyrychenko-dev/type-utils";
isArray([1, 2, 3]); // true
isReadonlyArray([1, 2, 3] as const); // true
isMap(new Map()); // true
isSet(new Set()); // true
isWeakMap(new WeakMap()); // true
isWeakSet(new WeakSet()); // trueObject and function
import { isFunction, isObject, isPlainObject } from "@okyrychenko-dev/type-utils";
isObject({}); // true
isObject([]); // true — arrays, Maps, Dates, class instances all pass
isObject(null); // false — null is excluded
isPlainObject({}); // true
isPlainObject([]); // false — not a `{}`/`Object.create(null)` object
isPlainObject(new Map()); // false
isFunction(() => undefined); // trueBuilt-ins
import { isDate, isError, isPromise, isRegExp } from "@okyrychenko-dev/type-utils";
isDate(new Date()); // true
isRegExp(/abc/); // true
isPromise(Promise.resolve()); // true
isPromise({ then: () => undefined }); // false — thenables are not Promise instances
isError(new TypeError("boom")); // true — subclasses includedAssertions
Assertions narrow their argument in place via TypeScript's asserts return type, and throw
when the value does not match.
import {
assertBoolean,
assertDefined,
assertFalse,
assertNumber,
assertString,
assertSymbol,
assertTrue,
} from "@okyrychenko-dev/type-utils";
assertString(value); // throws TypeError if `value` is not a string
assertNumber(value);
assertBoolean(value);
assertSymbol(value);
assertTrue(items.length > 0, "Expected at least one item.");
assertFalse(isLoading, "Cannot submit while loading.");
assertDefined(user, "User must be defined."); // narrows to NonNullable<T>Every assertion accepts an optional custom message as its last argument; each has a sensible default.
Exhaustiveness Checking
assertNever throws at runtime and fails the type-check if a switch/if chain does not
cover every case of a union:
import { assertNever } from "@okyrychenko-dev/type-utils";
type Status = "idle" | "loading" | "error";
function describe(status: Status): string {
switch (status) {
case "idle":
return "Idle";
case "loading":
return "Loading";
case "error":
return "Error";
default:
return assertNever(status); // compile error if a case is added and not handled here
}
}Utility Types
import type { Nullable, Nullish, Optional } from "@okyrychenko-dev/type-utils";
type A = Nullable<string>; // string | null
type B = Optional<string>; // string | undefined
type C = Nullish<string>; // string | null | undefinedimport type {
ElementOf,
Mutable,
NonEmptyArray,
Prettify,
ValueOf,
} from "@okyrychenko-dev/type-utils";
type Status = { readonly code: 200 | 404 | 500 };
type StatusCode = ValueOf<Status>; // 200 | 404 | 500
type Tags = NonEmptyArray<string>; // [string, ...string[]] — at least one element
type Item = ElementOf<readonly number[]>; // number
type MutableStatus = Mutable<Status>; // { code: 200 | 404 | 500 }
type Flat = Prettify<{ a: string } & { b: number }>; // { a: string; b: number }API Reference
All public APIs are available from the root package import.
| Area | Exports |
| --- | --- |
| Primitive guards | isString, isNumber, isFiniteNumber, isBoolean, isBigInt, isSymbol, isUndefined, isNull, isNullish, isDefined |
| Collection guards | isArray, isReadonlyArray, isMap, isSet, isWeakMap, isWeakSet |
| Object and built-in guards | isObject, isPlainObject, isFunction, isDate, isRegExp, isPromise, isError |
| Assertions | assertString, assertNumber, assertBoolean, assertSymbol, assertTrue, assertFalse, assertDefined, assertNever |
| Utility types | Nullable, Nullish, Optional, ValueOf, NonEmptyArray, ElementOf, Mutable, Prettify, Awaitable |
Development
npm install
npm run typecheck
npm run test:run
npm run buildLicense
MIT © Oleksii Kyrychenko
