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

@o3/typed

v0.1.3

Published

Simplistic and minimal runtime type checking system for Node.js applications

Downloads

7

Readme

Typed

Simplistic and minimal runtime type checking system for Node.js applications.

Build Status npm dependencies Status devDependencies Status peerDependencies Status

Typed is a minimal wrapper based type checking library for JavaScript to ensure user/developer facing functions are passed (and also return) their expected types. This is done in an attempt to reduce the amount human error in runtime environments.

Installing

via npm

npm i -S @o3/typed
# For fully featured runtime checking also install
npm i -S @o3/prop-types

How to use

Shared syntax pattern

You can define a subset of functions to accept ambiguous arguments like so:

// define your base library and/or utility functions
const add = (x, y) => x + y
const addOptional = (x, y = 3) => x + y;

And then wrap them using the typed functionality.

Allowing you to restrict your public functions to only accept specific input types and throw type errors when improper values are provided

const typed = require('@o3/typed/full');

module.exports = {
    // first two arguments must be string
    concat: typed(add, typed.string, typed.string)
    // first two arguments must be number
    addNumbers: typed(add, typed.number, typed.number),
    // first argument must be a number, while second can be ommited
    // but if passed must be a number
    addThree: addOptional(add, typed.number, typed.number.isOptional),
};

NOTE: typed/full uses a dependency called @o3/prop-types, which needs to be installed as a peer dependency. A more minimal version is exported at root level, which does not require this dependency, and instead opts to use a minimized lodash type build.

Using a alternative syntax, it is also possible to specify an expected resolving (return) type for a given function. For more complex functions this will ensure that input error won't return any unwanted inputs.

function complexAdd(x, y) {
    if (x === 0) {
    // zero sucks so let's do something awful
        // mostly for demonstrative purposes, I don't recommended writing
        // any production code like this ;)
        return null
    }

    // return forced integer add (base10)
    return parseInt(x, 10) + parseInt(y, 10);
}

// create (string or number) type to use in our definition
const stringOrNumber = typed.oneOfType([
    typed.string,
    typed.number,
]);

const addOnlyReturnNumber = typed(complexAdd, [
    // first and second param can be either a number or string
    stringOrNumber, stringOrNumber,
    // but must return a number
], typed.number);

addOnlyReturnNumber(2, 2) // returns expected type number (4)
addOnlyReturnNumber('2', 2) // returns expected type number (4)
addOnlyReturnNumber(0, 2) // throws due to invalid return value 'null'

Full format (recommended)

All the above examples are written in the full syntax, which requires the additional single dependency of @o3/prop-types, an adaptation of the Facebook React prop-types library. A more detailed write up of accepted syntax will come eventually, but I highly recommend you stick with their official documentation here.

The modifications made remove unneeded support for React components, add enforced isRequired on all known type definitions. To opt out of this, passing types.typeName.isOptional will allow voided values to be passed.

Basic format (minimal, no dependencies required)

While I'm making progress to reduce the amount of redundant abstractions within the @o3/prop-types library, by default this library exports a minimal version of the shown syntax, which relies on a minimized and tree-shaken port of all of lodash's known is{Type} exports.

The benefits of using this syntax are more strict type checking, since needing to rely on primitive checking that can sometimes be prone to strange quirks. The downside is that optional arguments are not really well supported due to it's highly strict nature.

Here is an example of the alternative basic format:

Example

const typed = require('@o3/typed');

const add = (x, y) => x + y;

// ensure first two paramaters meet expectation isNumber
// shorthand syntax
const addNumbers = typed(add, 'isNumber', 'isNumber');

// ensure that the parameter passed meets either expectation
const numberOrString = {
    anyOf: ['isNumber', 'isString'],
};

// longhand syntax
const addOnlyReturnNumber = typed(add, [numberOrString, numberOrString], 'isNumber');

Why make this

While searching the Internet for a solution to a problem I needed solving, I kept finding dynamic typing systems like TypeScript and Flow.

While these tools are great for ensuring that your internal code isn't calling any other code incorrectly, they don't seem to be orientated towards ensuring type compliance at runtime, which is an issue when allowing external developers to interface with your code.

I was also able to find several Babel runtime plug-ins that, to be frank, did not even meet the most minimal of my own expectations. I was underwhelmed by the quality of the runtime type-checking, since it seemed that the plugins would haphazardly enforce shallow type checking on all methods that included definitions, which in the case of Flow and TypeScript would be most methods within the codebase.

Performance wise this is not good as it adds at least several additional calls to every function invocation, which compounds quickly). Additionally, it also adds unneeded points of failure to each function call that was injected.

The solution employed by this library is intended to be applied to developer and user facing methods and calls, since those functions are most prone to input error, and should be the only functions (in a language like JavaScript) that realistically need runtime type checking.