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 🙏

© 2026 – Pkg Stats / Ryan Hefner

sweet-type-tools

v1.0.1

Published

A library that combines TypeScript and runtime checks for easier and safer JS coding.

Readme

Sweet TypeTools

npm license typescript

Sweet TypeTools is a lightweight runtime type library for JavaScript and TypeScript.

It extends JavaScript's native typeof with more practical runtime type detection (base), value refinement (x), and flexible value interpretation (adapt).

Contents

Installation

To install TypeTools, run the following command on a terminal in your project folder:

npm install sweet-type-tools

Philosophy

TypeTools focuses on runtime typing, with one main goal:

Making runtime typing clearer and simpler.

To achieve this, TypeTools comes with two runtime typing tools – essentially our alternatives to typeof :

  • sweetType() (essentially, our alternative to typeof)
  • sweetX()

This is part of a layered approach to typing, where you pick your tool according to the kind of runtime information you need.

The three layers are: base, x and adapt.

You can read more about the layers in their individual sections, or check out the quick reference table for a more detailed comparison.

Here is a brief overview:

  • Base Used to: Identify values Description: Extends typeof with a few additional labels, like 'array' and 'null'. Main tool: sweetType() for typing

  • X Used to: Refine values Description: Extends 'base' with 'x' labels, such as 'stringX' for empty strings (non-empty strings still return 'string'), numberX for 0 and NaN, arrayX,... etc. Main tool: sweetX() for typing

  • Adapt Used to: interpret and convert values Description: includes multiple tools like

    • is...() interpretation checks
    • if...() value adapters
    • to...() type converters

Base

sweetType() is the foundation of TypeTools.

Its purpose is simple:

Return a more practical runtime type than JavaScript's typeof.

It behaves almost exactly like JavaScript's native typeof, but fixes a few long-standing quirks that often make runtime type checks more confusing than they need to be.

For example, JavaScript reports all of these as "object":

typeof [];
// "object"

typeof {};
// "object"

typeof null;
// "object"

While technically correct, those values represent very different things in practice.

sweetType() separates them into their own runtime types:

sweetType([]);
// "array"

sweetType({});
// "object"

sweetType(null);
// "null"

It also treats NaN differently.

Although JavaScript considers NaN a "number", it cannot be used as a valid numeric value. Sweet TypeTools therefore treats it as an invalid number:

typeof NaN;
// "number"

sweetType(NaN);
// "undefined"

Everything else stays familiar:

sweetType("hello");
// "string"

sweetType(42);
// "number"

sweetType(true);
// "boolean"

sweetType(Symbol());
// "symbol"

sweetType(() => {});
// "function"

In short, sweetType() is simply a cleaner, more practical version of typeof.

Internally, this functionality is known as the Base layer. It provides the foundation on which the rest of Sweet TypeTools is built.

Base labels

The Base layer recognizes the following runtime type labels:

| Value | typeof | sweetType() | | :--- | :--- | :--- | | "hello" | "string" | "string" | | 42 | "number" | "number" | | true | "boolean" | "boolean" | | [] | "object" | "array" | | {} | "object" | "object" | | null | "object" | "null" | | 10n | "bigint" | "bigint" | | Symbol() | "symbol" | "symbol" | | () => {} | "function" | "function" | | undefined | "undefined" | "undefined" | | NaN | "number" | "undefined" |

Base checks

Every Base type has a matching helper function.

isString()
isNumber()
isBoolean()
isObject()
isArray()
isNull()
isUndefined()
isFunction()
isSymbol()
isBigint()

These helpers follow the same rules as sweetType().

For example:

isObject({});
// true

isObject([]);
// false

isObject(null);
// false

isNumber(12);
// true

isNumber(NaN);
// false

X

The X layer builds on the Base layer.

While sweetType() tells you what a value is, sweetX() tells you whether that value has additional characteristics that may deserve special handling.

For example, an empty string is still a string, and an empty array is still an array. However, in many applications these values carry a different meaning than their non-empty counterparts.

The X layer distinguishes those cases by introducing a small set of X labels.

sweetType("");
// "string"

sweetX("");
// "stringX"
sweetType([]);
// "array"

sweetX([]);
// "arrayX"
sweetType({});
// "object"

sweetX({});
// "objectX"
sweetType(0);
// "number"

sweetX(0);
// "numberX"

Rather than replacing the Base layer, X refines it.

This makes it easy to distinguish values that are technically valid, but may require different handling in your application.

X labels

The X layer currently recognizes the following refined labels:

| Base | X | | :--- | :--- | | "string" | "stringX" → empty or whitespace-only strings | | "array" | "arrayX" → empty arrays | | "object" | "objectX" → empty objects | | "number" | "numberX"0 or NaN | | "symbol" | "symbolX" → anonymous symbols |

All other Base labels remain unchanged.

X checks

Every X label has a matching helper function.

stringX()
arrayX()
objectX()
numberX()
symbolX()

Each helper returns true when the value satisfies the corresponding X refinement.

For example:

stringX("hello");
// true

stringX("");
// false

arrayX([1, 2]);
// true

arrayX([]);
// false

numberX(42);
// true

numberX(0);
// false

X resolvers

Like the Base layer, X also provides runtime type resolvers.

sweetX()
sweetXCheck()

These functions return or compare X-layer labels in the same way that sweetType() and sweetTypeCheck() work for the Base layer.

Adapt

The Adapt layer builds on both Base and X.

While the previous layers focus on identifying and refining values, Adapt focuses on interpreting and converting them.

Many values can be interpreted in more than one way.

For example:

  • "42" can be interpreted as the number 42
  • "TRUE" can be interpreted as the boolean true
  • " hello " may simply need normalization before further processing

The Adapt layer provides small, composable helpers that make these interpretations predictable and reusable.

Adapt function families

Adapt functions follow three naming patterns:

is...

Returns whether a value can be interpreted as something.

isNumeric("42")
// true

isBooleanString("TRUE")
// true

if...

Attempts the interpretation and returns the adapted value.

If adaptation is not possible, the return value depends on the adapter's configuration.

ifNumeric("42")
// 42

ifNumeric("hello")
// "hello"

ifBooleanString("TRUE")
// true

ifBooleanString("hello")
// "hello"

to...

Converts any value into a concrete target type using Sweet TypeTools value rules.

Unlike the if... adapters, these always return the target type.

toNumber("42")
// 42

toNumber("hello")
// 5

toBoolean([])
// false

toBoolean([1, 2])
// true

Adapt pipeline

Most Adapt helpers are intentionally built on top of one another.

Rather than duplicating logic, each helper performs a single step before delegating to the next one.

normalize
    ↓
is
    ↓
if
    ↓
to

For example, numeric adaptation follows this flow:

normalizeStringVal()
        ↓
isNumericString()
        ↓
ifNumericString()
        ↓
ifNumeric()
        ↓
toNumber()

This keeps the library consistent, easier to maintain, and easier to extend as new adapters are added.

Current adapters

The Adapt layer currently includes:

Helpers

normalizeStringVal()

Checks

isNumeric()
isNumericString()
isBooleanString()
isNullish()
isEmptyVal()

Adapters

ifNumeric()
ifNumericString()
ifBooleanString()

Type converters

toNumber()
toBoolean()

Quick Reference

| Value | typeof | sweetType() | sweetX() | Adapt (examples) |
| :--- | :---: | :---: | :---: | :--- |
| "hello" | string | string | string | isNumericString()falseifNumericString()"hello" |
| "" | string | string | stringX | isEmptyVal()truetoNumber()0 |
| "21" | string | string | string | isNumericString()trueifNumericString()21toNumber()21 |
| 420 | number | number | number | toBoolean()trueisEmptyVal()false |
| 0 | number | number | numberX | toBoolean()falseisEmptyVal()true |
| NaN | number | undefined | numberX | toBoolean()falsetoNumber()0isEmptyVal()true |
| null | object | null | null | toBoolean()falsetoNumber()0isEmptyVal()true |
| ["hello", "world", 2026] | object | array | array | toBoolean()truetoNumber()3 |
| [] | object | array | arrayX | toBoolean()falsetoNumber()0isEmptyVal()true |
| { hello: "world", year: 2026 } | object | object | object | toNumber()2 |
| {} | object | object | objectX | toNumber()0toBoolean()false |