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

s-types

v1.4.1

Published

Library-independent type checking similar to React Proptypes

Downloads

14

Readme

s-types

Library-independent type checking similar to React PropTypes

NPM version Dependencies build status NPM license Test Coverage

Installation

npm install --save s-types

Usage

import T from 's-types';

const fooType = T({
	foo: T.string,
	bar: [T.number, T.optional],
	baz: T.arrayOf(T.string)
});

const someObject = {
	foo: 'Hello',
	baz: ['world', '!']
};

fooType(someObject); // passes test, nothing logged to console

const fail = {
	foo: 'Hello',
	bar: 10,
	baz: [1, 2, 3] // !!!
};

// optional second argument to provide name for better error messages
fooType(fail, 'Bad Object');

/*
	Logs the following to stderr:

	Failed typecheck in Bad Object
	Expected prop 'baz' of type [array of strings]
	You provided 'baz' of type [array of numbers]

 */

Using an array of types in the schema allows for multiple types to be used. These are ORed together.

// Use an array to allow multiple types

const schema = T({
	foo: [T.string, T.number],
	bar: T.any
});

const someObject = {
	foo: 'Hello',
	bar: 5
};

const anotherObject = {
	foo: 5,
	bar: null
};

const badObject = {
	foo: null,
	bar: null
};

schema(someObject); // passes
schema(anotherObject); // passes
schema(badObject); // fails

The T.schema and T.arrayOf methods allow for nesting complex structures. For example:

const nestedRules = T({
	foo: T.string,
	bar: T.schema({
		baz: T.number,
		qux: T.arrayOf(T.arrayOf(T.number))
	})
});

const someObject = {
	foo: 'Hello',
	bar: {
		baz: 5,
		qux: [[1, 2], [3, 4]]
	}
};

nestedRules(someObject); // passes

The T.exact and T.oneOf methods allow to restrict to an exact value. For instance, a property that must contain the value "foo" could be defined like this:

const rules = T({
	x: T.exact('foo'),
	y: [T.exact('bar'), T.optional]
})

const obj1 = { x: 'foo' };
const obj2 = { x: 'foo', y: 'bar' };
const obj3 = { x: 'bar' };

rules(obj1); // passes
rules(obj2); // passes
rules(obj3); // fails

T.oneOf([a, b, c]) is a shorthand for [T.exact(a), T.exact(b), T.exact(c)]. It allows you to specify an array of allowed values.

const rules = T({
	x: T.oneOf(['foo', 'bar'])
})

const obj1 = { x: 'foo' };
const obj2 = { x: 'bar' };
const obj3 = { x: 'baz' };

rules(obj1); // passes
rules(obj2); // passes
rules(obj3); // fails

Types provided

  • T.any
  • T.array (alias T.arr)
  • T.arrayOf(type) Example: T.arrayOf(T.string)
  • T.boolean (alias T.bool)
  • T.date
  • T.exact Example: T.exact('foo')
  • T.function (alias T.fn)
  • T.integer (alias T.int)
  • T.nil (prop is null or undefined)
  • T.not(type) Example: T.not(T.string)
  • T.number (alias T.num)
  • T.null (alias T.NULL)
  • T.object (alias T.obj)
  • T.oneOf Example: T.oneOf(['foo', 'bar'])
  • T.optional (alias T.undefined)
  • T.schema (alias T.interface) Example: T.schema({ foo: T.string, bar: T.number })
  • T.string (alias T.str)

Custom types

If the provided types are not sufficient, you can provide a custom type checking function to s-types.

These functions take one argument (the value of the property to be type checked) and return a boolean to indicate whether it is valid or not.

The function must also be assigned a type attribute in order to allow for helpful error messages.

For example, T.string is defined as follows:

T.string = function(x) {
	return typeof x === 'string';
};

T.str.type = 'string';

To create a positiveNumber type, you could do the following:

function positiveNumber(x) {
	return typeof x === 'number' && x > 0;
}

postiveNumber.type = 'positive number';

const schema = {
	n: positiveNumber
};

const obj = {
	n: 12
};

T(schema)(obj); // passes

Usage in production

This should only be used in development and test environments, so when in production there is a mode that turns type checking into a noop.

Just set T.disabled to true before running any type checking.

One way to do this would be the following:

import T from 's-types';

T.disabled = process.env.node_env === 'production';

const fooType = T({
	foo: T.string
});

const fail = {
	foo: 5
};

// in a development environment, this logs an error message
// when process.env.node_env === 'production', this logs nothing
fooType(fail, 'Bad Object');

Usage in test environments

There is an option to change the typecheckers to throw rather than log to console.error. This can be enabled in test environments to make typechecking testable without having to check for messages in stdout.

import T from 's-types';

T.throws = true;

const fooType = T({
	foo: T.string
});

const fail = {
	foo: 5
};

fooType(fail, 'Bad Object'); // throws a TypeError

Why two functions?

The T(a)(b, c?); syntax allows typecheckers to be reused.

For example:

const UserType = T({
	age: T.number,
	email: T.string,
	emailVerified: T.boolean,
	name: T.string,
	friends: T.arrayOf(T.string)
});

const user1 = {
	age: 21,
	email: [email protected],
	emailVerified: false,
	name: 'John Doe',
	friends: ['user2']
};

const user2 = {
	age: 24,
	email: [email protected],
	emailVerified: true,
	name: 'Jane Doe',
	friends: ['user1']
};

UserType(user1, 'John Doe user object'); // passes
UserType(user2, 'Jane Doe user object'); // passes

// The `UserType` typechecker can now be exported and used elsewhere

Things to note

In most cases, the return value happens to be null when there are no errors or a string if a type mismatch occurred. For some structures, like T.schema, this does not always hold true and should not be relied upon. The only reliable output is whatever is logged to stderr (or the TypeError that is thrown if T.throws is enabled). In addition, when T.disabled is set to true, the return value will always be undefined.