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

type-assurance

v1.5.1

Published

Lightweight type guards and assertions

Downloads

44

Readme

🛡️ type-assurance

npm bundle size

Super lightweight TypeScript library to perform type checks at runtime.

  • Does only one thing: runtime type checking
  • Provides type guards and type assertions
  • Intuitive schema definition based on language literals
  • 100% test coverage

Example

Let's start with a simple example:

import { assert } from "type-assurance";

const userSchema = {
  name: String;
  email: String;
};

const user = await api.getUser(23);

// Throw if types don't match
assert(user, userSchema);

// The compiler now knows the type ...
console.log(user.name);

We can also infer a static TypeScript type from the runtime schema:

import { TypeFromSchema } from "type-assurance";

type User = TypeFromSchema<typeof userSchema>;

This yields the same type as if we had written it by hand:

type User = {
  name: string;
  email: string;
};

Sometimes all you need is a quick inline type-check. Use is instead of assert which acts as a type-guard:

import { is } from "type-assurance";

if (
  is(data, {
    body: {
      posts: [
        {
          id: Number,
          title: String,
        },
      ],
    },
  })
) {
  // We can now be certain that the given data
  // has the expected shape and the compiler
  // now knows about the types...
}

Installation

You can install the package from npm:

npm install type-assurance

🦕 The package is also published under https://deno.land/x/typeassurance for use with Deno.

Usage

The package exports the following main functions:

  • is(value, schema) – returns true if the value matches the schema. The return type is a type predicate that narrows the type down to the one described by the schema.
  • assert(value, schema) – throws a TypeError if the value does not match the schema. It is an assertion function that narrows the type down to the one described by the schema.
  • typeGuard(schema) – returns a function that can be used as type guard for the given schema.

The schema that is passed to both these functions looks like an example or blueprint of the expected type. It can be a deeply nested object or just a single value.

Primitives

You can use String, Number or Boolean as schema for primitive types:

is(42, Number); // ✅ true
is("42", Number); // ❌ false
is("foo", String); // ✅ true

This isn't particularly helpful on its own, but it makes sense when used to describe more complex shapes.

Objects

To specify objects, use an object where each value is again a schema:

import { typeGuard } from "type-assurance";

const isUser = typeGuard({
  post: {
    id: Number,
    author: {
      name: String,
    },
  },
});

const data = JSON.parse(`{
  "post": {
    "id": 23,
    "author": {
      "name": "Felix"
    }
  }
}`);

if (isUser(data)) {
  // data.post.author.name is a string ✅
}

Instances

You can use constructor functions as schema to check if an object is an instance of that type:

assert(data, {
  now: Date,
  pattern: RegExp,
});

This also works for classes:

class Person {
  constructor(public name: string) {
  }
}

const data: unknown = {
  user: new Person("Felix");
}

if (is(data, { user: Person })) {
  // data.user is a Person
};

NOTE: In the very unlikely case that you want to test for String, Number or Boolean objects, you have to use a function instead:

is("foo", String); // ✅ true
is(new String("foo"), String); // ❌ false
is(new String("foo"), (s) => s instanceof String); // ✅ true

Arrays

To specify an array of a certain type, wrap that type in an array:

assert(data, [Number]);
// data is of type number[]

Tuples

For tuples, provide an array with more than one item:

assert(value, [Number, String, Boolean]);
// value[0] is a number
// value[1] is a string
// value[2] is a boolean

Custom type guards

You can also use type guard functions as (nested) schemas:

/**
 * Type guard to test if the given value is SomeFancyType.
 */
function isSomeFancyType(v: unknown): v is SomeFancyType {
  // custom check goes here ...
}

assert(data, {
  id: Number,
  body: isSomeFancyType,
});

Literals

Finally, specific strings, numbers or boolean values are treated as literal types:

const personSchema = {
  type: "person",
  name: String
} as const;

const dogSchema = {
  type: "dog",
  name: String,
  breed: String,
}

if (is(data, dog)) {
  console.log(data.name "is a cute", data.breed);
}

Union Types

The package exports a union function to check if a value is of either of the given types:

import { union } from "type-assurance";

const taskSchema = {
  title: String,
  status: union("pending", "active", "done"),
};

Optional properties

You can use the optional helper for properties that aren't required:

import { optional } from "type-assurance";

const personSchema = {
  name: String
  address: optional(String)
};

Infer the type from a schema

You can convert a runtime schema into a static type:

import { TypeFromSchema } from "type-assurance";

const PersonSchema = {
  name: String;
  age: Number;
}

type Person = TypeFromSchema<typeof PersonSchema>;

License

MIT