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

introspect-typed

v1.0.0

Published

A small library to provide function type checks functionalities

Downloads

3

Readme

introspect-typed

Provides rudimentary type checking and function overloading in Javascript.

Install

npm install introspect-typed

API

matchType: Type checking individual values

Other methods (typeChecked, overload) are based on this functionality.

Direct match

    var matchType = require('introspect-typed').matchType;
    matchType(String, 'yes!');  // => true
    matchType(Number, 'no...'); // => false

Getting a matcher function

    var matchType = require('introspect-typed').matchType;
    var stringMatcher = matchType(String);
    stringMatcher('yes!');  // => true
    stringMatcher(22.145);  // => false

Custom types work as well

    var matchType = require('introspect-typed').matchType;
    function Custo () { this.type = 'custo'; }
    var custoMatcher = matchType(Custo);
    custoMatcher(new Custo());      // => true
    custoMatcher({type: 'custo'});  // => false

Matching against any type

Use Typed.Any if you want to match any value.

    var Typed = require('introspect-typed');
    var matchType = Typed.matchType;
    matchType(Typed.Any, undefined); // => true

Matching against several types

Use Typed.Either if you want to match several types.

    var Typed = require('introspect-typed');
    var matchType = Typed.matchType;
    matchType(Typed.Either(String, Number), 'string'); // => true
    matchType(Typed.Either(String, Number), 2);        // => true
    matchType(Typed.Either(String, Number), {});       // => false

Matching against a predicate

Use Typed.Matcher if you want to match with a predicate.

    var Typed = require('introspect-typed');
    var matchType = Typed.matchType;
    var type = Typed.Matcher(function (v) { return v.length === 2; });
    matchType(type, {length: 2}); // => true
    matchType(type, '12');        // => true
    matchType(type, [1,2]);       // => true
    matchType(type, '1');         // => false
    matchType(type, [1,2,3]);     // => false

Matching against an ES6 iterable

Iterables are objects with a Symbol.iterator property containing a function. In ES6, strings, arrays, sets, maps and generator functions, among others, are iterables.

Use Typed.Iterable if you want to match es6 iterables.

    var Typed = require('introspect-typed');
    var Iterable = Typed.Iterable;
    matchType(Iterable, []);    // => true
    matchType(Iterable, '12');  // => true
    matchType(Iterable, {});    // => true
    matchType(Iterable, 2);     // => false
    matchType(Iterable, null);  // => false

typeChecked: Type checking function calls

  var Typed = require('introspect-typed');
  var typeChecked = Typed.typeChecked;
  var Either = Typed.Either;
  function Custo () { this.type = 'custo'; }

Declare a type checked function by calling typeChecked with

  • an array of types,
  • the function you want to type check.
  var tcFn = typeChecked([Either(String, Number), Custo], function (s, c) {
    return s + c;
  });
  tcFn('string', new Custo()); // => 'string[object Object]'
  tcFn(Infinity, new Custo()); // => 'Infinity[object Object]'

Rest parameters

Check type for rest parameters by using Typed.Rest. In ES6:

var Rest = Typed.Rest;
var typedFn = typeChecked([String, Number, Rest(Either(Custom, String))],
  (s, n, ...cs) => ({ result: s.repeat(n), rest: cs.length });

In ES5:

  var Rest = Typed.Rest;
  var typedFn = typeChecked([String, Number, Rest(Either(Custom, String))],
    function (s, n) {
      var cs = [].slice.call(arguments, 2);
      return { result: s.repeat(n), rest: cs.length };
    });
  • Rest(String) will match all strings at the end of the arguments.
  • Rest(Any) will match anything at the end of the arguments.
  • Rest(Either(X,Y)) will match any number of Xs and Ys at the end of the arguments.

Note that Rest(...) must be the last element in the type array, otherwise an error will be thrown while matching.

Error management

By default, the typechecked function throws a TypeError when not given proper arguments.

  tcFn('string', {type:'custo'}); // => throws TypeError

You can set the error management behaviour yourself (at any time).

  tcFn.onError(function (error, args, types) {
    console.error(error);
  });

And set back the original throwing behaviour by calling onError with a falsey value.

  tcFn.onError(false);

overload: Overloading functions

Chaining methods

When creating an API, we often want our methods to accept different kinds of inputs, but the code that results from these checks is ugly and provides many occasions for bugs.

Instead, using overload, one can do the following:

  var overload = require('introspect-typed').overload;

  var createObj = overload(
    // This method is the default method, called when no other case
    // has matched
    function (obj) {
      obj.test = 1;
      return obj;
    }
  )
  .when('withName', // Here we define a 'withName' method in the overloading object
             [String, Object], // which matches calls with a String and an Object
    function (name,   obj,     o) // the last arg is the overloading object
    {
      obj.name = name;
      // We can use the overloading object to call other methods defined
      // for example the default method, passed to overload
      return createObj.default(obj);
    }
  )

  .when([String, String, Object], function (name, desc, obj, o) {
    obj.desc = desc;
    // Or we can use it to call named overloading methods.
    return createObj.withName(name, obj);
  });

Without the comments:

  var overload = require('introspect-typed').overload;

  var createObj = overload(function (obj) {
    obj.test = 1;
    return obj;
  }).when('withName', [String, Object], function (name, obj, o) {
    obj.name = name;
    return createObj.default(obj);
  }).when([String, String, Object], function (name, desc, obj, o) {
    obj.desc = desc;
    return createObj.withName(name, obj);
  });

Calling a named overloaded method directly bypasses the type check.

To have a completely type checked method, one could do this instead:

  var overload = require('introspect-typed').overload;
  var typeChecked = require('introspect-typed').typeChecked;

  var createObj = overload([Object], function (obj) {
    obj.test = 1;
    return obj;
  })
  .when([String, Object], function (name, obj, o) {
    obj.name = name;
    return createObj(obj);
  })
  .when([String, String, Object], function (name, desc, obj, o) {
    obj.desc = desc;
    return createObj(name, obj);
  });

The calls to overload with arguments matching [Array, Function] are equivalent to overload(typeChecked(types, fn)).

Complete overloading

  var overload = require('introspect-typed').overload;

  var fn = overload(function () { return this; })

    // give a number : increments it
    .when([Number],
      function (a) { return a + 1; })

    // give two numbers : multiply them
    .when([Number, Number],
      function (n1, n2) { return n1 * n2; })

    // give two strings: join them with '-'
    .when([String, String],
      function (s1, s2) { return s1 + '-' + s2; })

    // give 3 strings: join them with '!'
    .when([String, String, String],
      function (s1, s2, s3) { return [s1,s2,s3].join('!'); })

    // returns the length for a String or an Array
    .when([Either(String,Array)],
      function (v) { return v.length; })

    // logs arguments when there are 4 of them
    .when([Any, Any, Any, Any],
      function () { console.log(arguments); return arguments[3]; })

    // give a number and a string: repeat the string n times
    .when([Number, String],
      function (n, s) { return s.repeat(n); });

Calling this method with different kinds of arguments changes its behaviour.

    expect(fn('2','57', 'x')).to.be.equal('2!57!x');
    expect(fn('2','57')).to.be.equal('2-57');
    expect(fn(2,'57')).to.be.equal('5757');
    expect(fn(2,57)).to.be.equal(2*57);
    expect(fn(42)).to.be.equal(43);

The this value is conserved.

    expect(fn.apply(42, [])).to.be.equal(42);

build

The build function allows to create a new Typed context.

This allows to modify the matchType function, to pass more cases to the type checking.

    var build = require('introspect-typed').build;
    var newTypedContext = build();
    var matchType = newTypedContext.matchType;

    var Truthy = {};

    expect(matchType(Truthy, 1)).to.be.false;
    expect(matchType(Truthy, null)).to.be.false;

    matchType.addTypeMatchCase({
      case: function (type) { return type === Truthy; },
      match: function (type) { return function (val) { return !!val }; }
    });

    expect(matchType(Truthy, 1)).to.be.true;
    expect(matchType(Truthy, null)).to.be.false;