Reusable TypeScript type guards for narrowing unknown values in application and library code.
npm install @coderrob/typescript-type-guardsThe package and its development tooling require Node.js ^20, ^22, or ^24.
import {
createEnumGuard,
createTypeGuard,
isArrayOf,
isDefined,
isNonEmptyString,
isNumber,
isPlainObject,
isString,
} from '@coderrob/typescript-type-guards';
const values: unknown[] = ['a', 'b', 'c'];
if (isArrayOf(isString)(values)) {
values.map((value) => value.toUpperCase());
}
const maybeName: string | null | undefined = 'Ada';
if (isDefined(maybeName) && isNonEmptyString(maybeName)) {
console.log(maybeName);
}
enum Status {
Active = 'ACTIVE',
Inactive = 'INACTIVE',
}
const isStatus = createEnumGuard(Status, 'Status');
if (isStatus('ACTIVE')) {
console.log('valid enum value');
}
class User {
constructor(public readonly id: number) {}
}
const isUser = createTypeGuard(User);
const input: unknown = new User(1);
if (isUser(input) && isNumber(input.id)) {
console.log(input.id);
}
const maybeConfig: unknown = { retries: 3 };
if (isPlainObject(maybeConfig)) {
console.log(maybeConfig.retries);
}- Primitive guards:
isString,isNumber,isBoolean,isBigInt,isSymbol,isNull,isUndefined,isNullish,isNullOrUndefined - Numeric guards:
isFiniteNumber,isInteger,isNaN - Collection guards:
isArray,isNonEmptyArray,isArrayOf,isNonEmptyArrayOf,isMap,isSet - Object-like guards:
isObject,isPlainObject,isFunction,isError,isRegExp,isDate,isValidDate,isPromise,isThenable - Utility guards:
isDefined,isNonEmptyString,createTypeGuard,createEnumGuard
The published package exposes a single public entrypoint with both ESM and CommonJS support:
import { isString } from '@coderrob/typescript-type-guards';const { isString } = require('@coderrob/typescript-type-guards');Package metadata can also be resolved explicitly when needed:
const packageMetadata = require('@coderrob/typescript-type-guards/package.json');import packageMetadata from '@coderrob/typescript-type-guards/package.json' with { type: 'json' };Type declarations are emitted during build and included in the published package.
The published tarball also includes the root README.md, LICENSE, and package.json. Those top-level files are included automatically by npm and are not copied into dist/.
Run the local micro-benchmarks with:
npm run benchLatest local run on Windows 11 (10.0.26200.0) with Node.js v22.19.0:
| Guard | Average latency | Average throughput |
|---|---|---|
isString on string |
39.02 ns |
19,608,415 ops/s |
isNumber on number |
37.68 ns |
20,371,720 ops/s |
isPlainObject on object |
37.85 ns |
20,250,036 ops/s |
createEnumGuard result on enum value |
39.55 ns |
19,332,792 ops/s |
These are indicative micro-benchmark results from a single local machine. They are useful for relative comparisons inside this repository, not as a guarantee of identical performance in other runtimes or workloads.
See also:
CONTRIBUTING.mdfor local setup, verification, and contribution expectationsCHANGELOG.mdfor release history
npm run verify
npm run test:coverage
npm run build
npm run bench
npm run changeset
npm run release:version
npm run release:changesets
npm run publish:packagenpm run format:check
npm run lint
npm run typecheck
npm test
npm run build
npm run test:package
npm run package:quality
npm run test:coveragenpm run changesetcreates a release note entry for a package change.npm run release:versionapplies pending changesets and updates the changelog.npm run release:changesetsruns the full verification stack, coverage, and then publishes through Changesets. In GitHub Actions, this release path also publishes with provenance.npm run publish:packageperforms a direct npm publish with a dry-run pack check first..github/workflows/release.ymlis a manualworkflow_dispatchworkflow for optional release publishing.
