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

primitive-predicates

v2.1.4

Published

A simple TypeScript library providing type guards for the primitive types in JavaScript.

Downloads

540

Readme

primitive-predicates

codecov Build Package status License

A simple TypeScript library providing type guards for the primitive types in JavaScript.

What is it?

TypeScript will use certain clues to narrow the typing information down as much as it can before runtime. To help the compiler do this, TypeScript provides two features that this library uses to provide convenience functions:

  1. Type predicate functions
  2. Type assertion functions

How to install

To install, just run:

npm install primitive-predicates

Available functions

  • assertIsObject
  • isObject
  • assertIsArray
  • isArray
  • assertIsArrayOf
  • isArrayOf
  • assertIsString
  • isString
  • assertIsNumber
  • isNumber
  • assertIsBoolean
  • isBoolean
  • assertIsNull
  • isNull
  • assertIsUndefined
  • isUndefined
  • assertIsBigInt
  • isBigInt
  • assertIsSymbol
  • isSymbol
  • assertHasProperty
  • hasProperty

Basic usage

Everything is available from the top level. Here's an example of how to import the functions:

import { assertIsString } from "primitive-predicates";

const [firstEntry, , , fourthEntry] = someCommaSeparatedString.split(",");
// Both could either be a string, or undefined
assertIsString(firstEntry);
assertIsString(fourthEntry);
// Both are now recognized as strings (or would've thrown an error)

Checking for properties

Once an object is found to be of type object, TypeScript won't just allow access to properties it doesn't know are there or not. Luckily, this library also provides convenient functions for checking this, as well:

const obj: object = {};

assertHasProperty(obj, "thing");
// Now recognizes obj as type: object & Record<"thing", unknown>
assertIsString(obj.thing);
// Now recognizes obj as having a 'thing' property of type 'string'
console.log(obj.thing.toUppercase());

Catching Assertion Errors

Each type assertion function throw their own type of error. Each of those errors, however, extends AssertionError (defined and provided by this library), which itself extends TypeError. This should make it convenient for catching thrown errors as desired while also allowing them to be easily distinguished from other types of errors.

To import the error classes to compare against during a try/catch, simply import them from the package like so:

import { StringAssertionError } from "primitive-predicates";

These are the available error types, grouped according to their inheritance:

  • AssertionError
    • ObjectAssertionError
      • ArrayAssertionError
          • ArrayMemberAssertionError
    • StringAssertionError
    • NumberAssertionError
    • BooleanAssertionError
    • NullAssertionError
    • UndefinedAssertionError
    • BigIntAssertionError
    • SymbolAssertionError
    • PropertyAssertionError

Predicates

Type predicate functions take in an argument, and return a boolean that is true if the passed argument was the expected type, or false if it isn't.

For example:

import { isString } from "primitive-predicates";

function doSomething(myArg: string): number;
function doSomething(myArg: number): string;
function doSomething(myArg: any): number | string {
  if (isString(myArg)) {
    return 42;
  }
  return "you gave me a number";
}

const aNumber = doSomething("definitely a string"); // The compiler will know 'aNumber' is a number.
const aString = doSomething(3); // The compiler will know 'aString' is a string.

Assertions

Type assertion functions work much the same way as predicates, except they throw an error if the argument passed isn't of the expected type. This is particularly useful when you're pretty sure something is a given type but you don't wanna have to mess around with flow control. Simply plop an assertion down and everything after it assumes the value is that type.

For example:

import { assertIsString } from "primitive-predicates";

function printUppercase(myArg: any) {
  assertIsString(myArg);
  console.log(myArg.toUppercase()); // compiler doesn't complain
}

isArrayOf and assertIsArrayOf

These are more advanced than the other predicates and assertions. These take a second argument to check against each member of the array. isArrayOf and assertIsArrayOf both accept a type predicate for this argument, but assertIsArrayOf can also accept a type assertion. If a type assertion is provided, assertIsArrayOf will make no attempt to stop any errors that assertion might throw. However, if the object passed is an array, and a type predicate was passed, but its members fail the type predicate check, it will throw an ArrayMemberAssertionError which extends the normal ArrayAssertionError.

Here's some examples of how these are used:

let stringArray: unknown = ["hello", "world"];
if (isArrayOf(stringArray, isString)) {
  // We're guaranteed that stringArray is an array of strings here
}
try {
  const obj: unknown = [123]
  assertIsArrayOf<string>(obj, isString)
} catch (err) {
  if (err instanceof ArrayAssertionError) {
    // the object is not an array at all.
    // NOTE: In this example, this WILL NOT be the error thrown.
  } else if (err instanceof ArrayMemberAssertionError) {
    // the object is an array, but one or more of its members are not strings
    // NOTE: In this example, this WILL be the error that will be thrown.
  } else if (err instanceof StringAssertionError) {
    // the object is an array, but one or more of its members are not strings
    // NOTE: In this example, this WILL NOT be the error thrown.
  }
}
try {
  const obj: unknown = [123]
  assertIsArrayOf<string>(obj, assertIsString)
} catch (err) {
  if (err instanceof ArrayAssertionError) {
    // the object is not an array at all.
    // NOTE: In this example, this WILL NOT be the error thrown.
  } else if (err instanceof ArrayMemberAssertionError) {
    // the object is an array, but one or more of its members are not strings
    // NOTE: In this example, this WILL NOT be the error thrown.
  } else if (err instanceof StringAssertionError) {
    // the object is an array, but one or more of its members are not strings
    // NOTE: In this example, this is the error that WILL be thrown.
  }
}

object and null

The typeof operator, as its name suggests, returns the name of the type of the value provided as a string. For example, typeof "hello" would return "string". But there's a long existing "bug" in JavaScript that results in typeof null returning "object". This manifests in TypeScript in many ways that can prove to be frustrating.

TypeScript tries to help out by preventing us from passing null where things are explicitely typed as object, but things can get messy and confusing. In order to properly check that something is actually an object (and not null) we have to do the following:

const someVar: any = {};
if (someVar !== null && typeof someVar === "object") {
  // 'someVar' is still recognized as type 'any'
  someVar.thing(); // Compiler doesn't complain
}

The problem is that even after that check, the compiler will still see it as type any. This can be a real problem when trying to be very strict with the typing, since the compiler won't be making sure you can only reference properties it knows are there.

Luckily, this package provides that with convenience functions:

const someVar: any = {};
if (isObject(someVar)) {
  // 'someVar' is now recognized as type 'object'
  someVar.thing(); // Compiler complains
}

Note: Checking the type directly can work to determine whether or not the value is actually an object if the original type is unknown, because unknown is inherently more restrictive than any. The functions provided by this library still simplify the logic a bit and reduce the need for checking certain edge cases ("We test it so you don't have to!").