npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

isguard-ts

v3.1.3

Published

a typescript library for building type guards quickly while maintaining type safety

Readme

isguard-ts

A powerful typescript library that helps you build type guards quickly while maintaining type safety.

isguard-ts utilizes the typescript compiler to ensure that its type guards are aligned with the guarded type. For example, when making a change to your type, isguard-ts will inform you to update your type guard as well.

Installation

npm install isguard-ts

Table of Contents

Basic Usage

TypeGuard<T>

The most basic type - represents a type guard of T

type TypeGuard<T> = (value: unknown) => value is T;

isType

Helps you create type guards for types and interfaces

type Person = {
	name: string;
	age: number;
};

const isPerson = isType<Person>({
	name: isString,
	age: isNumber,
});

isPerson({ name: "Hello", age: 6 }); // true

Best Practice

Pass the generic type argument into isType Otherwise optional fields might have an unexpected behavior

isOptional

Helps you create type guards for optional (potentially undefined) types

isOptional(isNumber); // or isNumber.optional();

isMaybe

Helps you create type guards for nullable (potentially null) types

isMaybe(isNumber); // or isNumber.maybe();

isArray

Helps you create type guards for arrays

isArray(isBoolean); // or isBoolean.array();

isLiteral

Helps you create type guards for literals

const isHello = isLiteral("Hello");
const is12 = isLiteral(12);

isLiteral can receive multiple values

const directions = ["up", "down", "left", "right"] as const;
type Direction = (typeof directions)[number];

const isDirection = isLiteral(...directions) satisfies TypeGuard<Direction>;

Best Practice

Use the satisfies keyword on the result of isLiteral when passing multiple values This ensures the result is of the expected type

isUnion

Helps you create type guards for unions

type A = { a: number };
type B = { b: string };
type C = A | B;

const isA = isType<A>({ a: isNumber });
const isB = isType<B>({ b: isString });

isUnion(isA, isB) satisfies TypeGuard<C>; // or isA.or(isB);

Best Practice

Use the satisfies keyword on the result of isUnion This ensures the result is of the expected type

isIntersection

Helps you create type guards for intersections

type A = { a: number };
type B = { b: string };
type C = A & B;

const isA = isType<A>({ a: isNumber });
const isB = isType<B>({ b: isString });

isIntersection(isA, isB) satisfies TypeGuard<C>; // or isA.and(isB);

Best Practice

Use the satisfies keyword on the result of isIntersection This ensures the result is of the expected type

isRecord

Helps you create type guards for records

const timeUnits = ["second", "minute", "hour"] as const;
type TimeUnit = (typeof timeUnits)[number];

isRecord(timeUnits, isNumber);
// Record<TimeUnit, number>

isPartialRecord

Works just like isRecord but allows for undefined values

const timeUnits = ["second", "minute", "hour"] as const;
type TimeUnit = (typeof timeUnits)[number];

isPartialRecord(timeUnits, isNumber);
// Partial<Record<TimeUnit, number>>

isIndexRecord

Works just like isRecord but checks only the values and not the keys

isIndexRecord(isNumber); // or isNumber.indexRecord();
// Record<PropertyKey, number>

isLazy

Helps you lazy load a type guard. Useful for:

  • Resolving undefined errors due to circular imports
  • Creating type guards for recursive types
import { isPerson } from "./some-module";

const isPeople = isLazy(() => isPerson).array();

In the example above isPerson, imported from ./some-module, might be undefined when isPeople is being created, due to circular imports. So isPerson.array() would throw an error. isLazy solves this issue by accessing isPerson only when needed.

isTuple

Helps you create type guards for tuples

type Row = [number, string?];

const isRow = isTuple<Row>([isNumber, isString.optional()]);

isRow([6, "Hello"]); // true
isRow([6]); // true
isRow(["Hello", "Bye"]); // false

Best Practice

Pass the generic type argument into isTuple Otherwise optional fields might have an unexpected behavior

isEnum

Helps you create type guards for enums

enum Direction {
	up = 0,
	down = 1,
	left = 2,
	right = 3,
}

const isDirection = isEnum(Direction);

isDirection(Direction.up); // true
isDirection(2); // true
isDirection("hello"); // false

isSet

Helps you create type guards for sets

isSet(isNumber); // or isNumber.set();
// Set<number>

isMap

Helps you create type guards for maps

isMap(isString, isBoolean);
// Map<string, boolean>

isInstanceof

Helps you create type guards for classes

abstract class Animal { }
class Dog extends Animal { }

const isAnimal = isInstanceof(Animal);
const isDog = isInstanceof(Dog);

isRefine

Helps you refine existing type guards. Can be used for:

  • Branded types (like Email, PositiveNumber and more)
  • Template literals (like `Bye ${string}`)
type Farewell = `Bye ${string}`;

const isFarewell = isRefine(isString, (value: string): value is Farewell => {
	return value.startsWith("Bye ");
});

Warning

using isRefine can be unsafe because it let's you implement potentially false logic Use at your own risk.

Built-in Utility Type Guards

const isNumber: TypeGuard<number>;
const isBigint: TypeGuard<bigint>;
const isString: TypeGuard<string>;
const isBoolean: TypeGuard<boolean>;
const isSymbol: TypeGuard<symbol>;
const isFunction: TypeGuard<Function>;
const isPropertyKey: TypeGuard<PropertyKey>;

const isDate: TypeGuard<Date>;
const isRegExp: TypeGuard<RegExp>;
const isObject: TypeGuard<object>;
const isError: TypeGuard<Error>;
const isEvalError: TypeGuard<EvalError>;
const isRangeError: TypeGuard<RangeError>;
const isReferenceError: TypeGuard<ReferenceError>;
const isSyntaxError: TypeGuard<SyntaxError>;
const isTypeError: TypeGuard<TypeError>;
const isURIError: TypeGuard<URIError>;

const isNull: TypeGuard<null>;
const isUndefined: TypeGuard<undefined>;
const isNil: TypeGuard<null | undefined>;

const isTrue: TypeGuard<true>;
const isFalse: TypeGuard<false>;

const isUnknown: TypeGuard<unknown>;
const isNever: TypeGuard<never>;

Advanced Usage

Generic Types

When creating type guards for generic types, you need to create your own TypeGuard generator

type ValueHolder<T> = {
	value: T;
};

const isValueHolder = <T>(isValue: TypeGuard<T>) => {
	return isType<ValueHolder<T>>({
		value: isValue,
	});
};

const isNumberHolder = isValueHolder(isNumber);

Recursive Types

One way to build recursive type guards is by using isLazy

type Json =
	| number
	| string
	| boolean
	| null
	| Json[]
	| { [key: string]: Json; };

const isJson: TypeGuard<Json> = isUnion(
	isNumber,
	isString,
	isBoolean,
	isNull,
	isLazy(() => isJson).array(),
	isLazy(() => isJson).indexRecord(),
);
type Tree = {
	value: number;
	left?: Tree;
	right?: Tree;
};

const isTree: TypeGuard<Tree> = isType<Tree>({
	value: isNumber,
	left: isLazy(() => isTree).optional(),
	right: isLazy(() => isTree).optional(),
});

There is a less recommended way using a getter

const isTree: TypeGuard<Tree> = isType<Tree>({
	value: isNumber,
	get left() {
		return isTree.optional();
	},
	get right() {
		return isTree.optional();
	},
});

Important

Annotate the recursive guard to avoid typescript errors

Plugins

Zod

Any TypeGuard has a .zod() method that returns a zod schema which represents the guarded type. To use this feature you must have zod installed through npm. The supported versions of zod start with [email protected] and end with [email protected] (not included)

const ZodNumber = isNumber.zod(); // same as z.number()

type Person = {
	name: string;
};

const isPerson = isType<Person>({
	name: isString,
});

const ZodPerson = isPerson.zod(); // same as z.object({ name: z.string() })

Important

The schema returned by .zod() might not exactly represent the guarded type in certain edge cases. For example: isNumber(NaN) returns true while z.number() marks NaN as invalid.

The differences vary between zod versions, but these are the most common

  • Non finite numbers (NaN, Infinity, -Infinity) are valid when using isguard-ts but invalid when using zod
  • zod ignores symbol property keys while isguard-ts doesn't