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 🙏

© 2024 – Pkg Stats / Ryan Hefner

handy-types

v2.1.0

Published

A collection of small utility functions to check variable types

Downloads

10,112

Readme

Handy-Types

Module Type Npm Version GitHub Tag GitHub Issues

A simple and lite weight validation library to reduce boilerplate in your JavaScript / TypeScript validation code.

It consists of many utility type predicate functions like "integer", "positive_integer", "non_empty_string", "plain_object" and so on. Still not impressed? How about "string[]" to represent a string array or "non_empty_string | non_empty_string[]" to represent a non empty string or an array of non empty string(s)? TypeScript type annotation is also supported. The library is fully tested and has 100% test coverage.

Importing

The library uses UMD module system so it's compatible with all JavaScript module systems.

JavaScript / TypeScript

// es modules
import { is, assert, cache, handyTypes, typeNames } from "handy-types";

// commonjs modules
const { is, assert, cache, handyTypes, typeNames } = require("handy-types");

In HTML with the <script> tag

<script src="https://unpkg.com/handy-types"></script>
<!-- it will be available as a global object by the name "handy_types" -->

Usages

This library exposes the following 5 entities

  1. handyTypes: An object containing all the type predicate functions. For example, handyTypes.positive_integer(2); // true.

  2. typeNames: An object containing all the names of predicate functions of handyTypes. For example: typeNames["positive_integer"]; // "Positive Integer". It may be used to generate meaningful error messages.

  3. is: a predicate function that uses all the functions in handyTypes object to validate data. For example, is("string", "a string"); // true. It has a cache method with the same function signature as itself. The it.cache() method can be used to cache parsed schemas to improve performance.

  4. assert: a utility function similar to is but used for making assertions. It also has a cache method similar to is.

  5. cache: An object used to manage schema caches of is.cache() and assert.cache() functions.

Type schema syntax

A type schema is a string passed into the is and assert function to represent a type. There are three types of type schema:

  1. Basic: Just a simple handy type name such as "string", "non_empty_array" etc.

  2. Array: If we add the "[]" suffix after any handy type name it represents an array of that type. So "string[]" would represent and array of string.

  3. Union: We can combine two or more type schema with a pipe "|" character to represent an union. For example, "string | string[]" to represent a string or an array of string(s).

Usages of is()

The is predicate function has the following signature.

interface Is {
  <Type>(schema: string, value: unknown): value is Type;
  cache<Type>(schema: string, value: unknown): value is Type;
}

The reason it's a generic function with a type parameter named Type is to support typescript type annotation. For example:

TypeScript Example

let value: unknown;

if (is<string | string[]>("non_empty_string | non_empty_string[]", value)) {
  value; // let value: string | string[]
}

In the if block the type of value variable is string | string[]. We've to pass the type of value (string | string[]) manually because it's not possible to process an union schema with TypeScript to determine it's actual type.

But if this seems a little bit of extra work to you then you can use the basic type predicate functions directly from the handyTypes object . For example:

let value: unknown;

if (handyTypes.integer(value)) {
  value; // let value: number
}

Here in the if block the type of value variable will be set to number automatically. But the downsides of this approach are:

  1. We can't use array or union type schemas
  2. handyTypes.integer(value) doesn't seem intuitive because most of the time a predicate function starts with the word is as a convention.

JavaScript Example

For JavaScript just remove the generic type argument.

const hobbies = "programming";
if (is("non_empty_string | non_empty_string[]", hobbies)) {
  hobbies;
  // so `hobbies` is either a non_empty_string or a
  // non_empty_string array
}

Usages of is.cache()

Use the is.cache() function instead of is for array and union schemas to improve performance. It will parse and cache the schema so that it doesn't have to waste time parsing the same schema again and again.

TypeScript Example

if (is.cache<string | string[]>("string | string[]", value)) {
  value; // here value is of type: string | string[]
}

JavaScript Example

if (is.cache("string | string[]", value)) {
  value; // here value is of type: string | string[]
}

Usages of assert

We can use the assert function to make assertions. It has the following function signature:

interface Assert {
  <Type>(
    schema: string,
    value: unknown,
    errorInfo?: ErrorInformation
  ): asserts value is Type;
  cache<Type>(
    schema: string,
    value: unknown,
    errorInfo?: ErrorInformation
  ): asserts value is Type;
}

Here ErrorInformation refers to the interface below.

interface ErrorInformation {
  name?: string;
  message?: string;
  code?: string | number;
  otherInfo?: object;
}

Just like the is function it takes a type schema and the variable we're making assertion on as it's first and second arguments respectively. Then we can provide more information in the errorInfo object to customize the error object.

Examples:

let value: unknown;

assert<number>("integer", value);
// throws error: `Value must be of type Integer`

assert<number>("integer", value, {
  name: "Age",
  code: "INVALID_AGE",
});
// throws error: `Age must be of type Integer`, with code: "INVALID_AGE"

// Use custom message instead of generating one
assert<string>("non_empty_string", value, {
  message: "Invalid path",
  otherInfo: {
    path: value,
    errorId: -3,
  },
});
// throws error: `Invalid path` , path: undefined, errorId: -3

Usages of assert.cache()

It serves the same purpose as is.cache(), it caches parsed schemas.

assert.cache<string | string[]>(
  "non_empty_string | non_empty_string[]",
  value,
  { name: "hobbies" }
); // use caching for improved performance

Usages of the cache object

The cache object can be used to manage schema caches. It has the following interface.

Readonly<{
  readonly size: number;
  has(schema: string): boolean;
  delete(schema: string): boolean;
  clear(): void;
}>;

Examples:

console.log(cache.size); // 0

const schema = "integer | integer[]";

is.cache<number | number[]>(schema, 23);

console.log(cache.size); // 1

console.log(cache.has(schema)); // true

// use the delete method to delete a specific schema cache
cache.delete(schema); // true

console.log(cache.size); // 0

// clear all caches
cache.clear();

All handy types

Below are the lists of all the type predicates available in the handyTypes object.

Base Types

| Type Name | Full Name | Implementation | | ----------- | ----------- | --------------------------------------------------- | | boolean | Boolean | typeof value === "boolean" | | symbol | Symbol | typeof value === "symbol" | | string | String | typeof value === "string" | | object | Object | typeof value === "object" | | big_integer | Big Integer | typeof value === "bigint" | | function | Function | typeof value === "function" | | undefined | Undefined | typeof value === "undefined" | | number | Number | typeof value === "number" && !Number.isNaN(value) |

Note: The type number is not just typeof value === "number"!

Number Types

| Type Name | Full Name | Implementation | | ------------------- | ------------------- | -------------------------------- | | finite_number | Finite Number | Number.isFinite(n) | | positive_number | Positive Number | handyTypes.number(n) && n > 0 | | non_negative_number | Non Negative Number | handyTypes.number(n) && n >= 0 | | negative_number | Negative Number | handyTypes.number(n) && n < 0 | | non_positive_number | Non Positive Number | handyTypes.number(n) && n <= 0 |

Integer Types

| Type Name | Full Name | Implementation | | -------------------- | -------------------- | ------------------------------- | | integer | Integer | Number.isInteger(i) | | safe_integer | Safe Integer | Number.isSafeInteger(i) | | positive_integer | Positive Integer | Number.isInteger(i) && i > 0 | | non_negative_integer | Non Negative Integer | Number.isInteger(i) && i >= 0 | | negative_integer | Negative Integer | Number.isInteger(i) && i < 0 | | non_positive_integer | Non Positive Integer | Number.isInteger(i) && i <= 0 |

Bytewise Integer Types

| Type Name | Full Name | Range | | ---------------------- | ----------------------- | --------------------------------------- | | 8bit_integer | 8 Bit Integer | -128 to 127 | | 8bit_unsigned_integer | 8 Bit Unsigned Integer | 0 to 255 | | 16bit_integer | 16 Bit Integer | -32,768 to 32,767 | | 16bit_unsigned_integer | 16 Bit Unsigned Integer | 0 to 65,535 | | 32bit_integer | 32 Bit Integer | -2,147,483,648 to 2,147,483,647 | | 32bit_unsigned_integer | 32 Bit Unsigned Integer | 0 to 4,294,967,295 |

Array Types

| Type Name | Full Name | Implementation | | --------------- | --------------- | -------------------------------------------- | | array | Array | Array.isArray(value) | | non_empty_array | Non-Empty Array | Array.isArray(value) && value.length !== 0 |

Object Types

| Type Name | Full Name | Implementation | | --------------- | --------------- | ---------------------------------------------------------------------- | | non_null_object | Non-Null Object | typeof value === "object" && value !== null | | plain_object | Plain Object | typeof value === "object" && value !== null && !Array.isArray(value) |

String Types

| Type Name | Full Name | Implementation | | ------------------------ | -------------------------- | ---------------------------------------------------- | | non_empty_string | Non-Empty String | typeof value === "string" && value !== "" | | trimmed_non_empty_string | Non-Empty String (trimmed) | typeof value === "string" && !!value.trim().length |

Other Types

| Type Name | Full Name | Implementation | | ----------- | ------------ | ----------------------------------------- | | nan | Not A Number | Number.isNaN(value) | | any | Any | true // returns true for any value | | nullish | Nullish | value === null \|\| value === undefined | | non_nullish | Non-Nullish | value !== null && value !== undefined |

If you find any bug or want to improve something please feel free to open an issue. Pull requests are also welcomed.