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 🙏

© 2025 – Pkg Stats / Ryan Hefner

matches-shape

v2.1.0

Published

A tool for testing whether an object is of a given shape

Downloads

6

Readme

Shape Matcher

A lightweight tool, modeled after React PropTypes declarations, for asserting the shape of any type of data. Originally designed for testing API responses, Shape provides a simple interface for testing if data looks right, and accessing any failures.

CircleCI

Methods

Matches

Given a shape object (built using Shape's PropType like type functions), and some data, shape.matches(data) will return whether or not the two match.

Passing case:

import Shape, { string, number, format, oneOf, regexes } from 'matches-shape';
const shape = new Shape([{
  name: string,
  age: number,
  birthDate: format(regexes.iso8601),
  friends: [string],
  gender: oneOf(['female', 'male'])
}]);
shape.matches([{
  name: 'John',
  age: 4,
  birthDate: '2012-04-03T06:25:18.234Z',
  friends: ['Sally', 'Bob'],
  gender: 'male'
}])
// => true // It checks out!

Failing case:

import Shape, { string, number, format, oneOf, regexes } from 'matches-shape';
const shape = new Shape([{
  name: string,
  age: number,
  birthDate: format(regexes.iso8601),
  friends: [string],
  gender: oneOf(['female', 'male'])
}]);
shape.matches([{
  name: 'John',
  age: 4,
  birthDate: '2012-04-03T06:25:18.234Z',
  friends: ['Sally', 'Bob'],
  gender: 'not-a-gender'
}])
// => false // Expected value at gender to be one of 'female' or 'male', but found 'not-a-gender'.

Last Non Matches

Shape also provides a simple API (to be improved) for seeing what failed in the match:

import Shape, { string, number, format, oneOf, oneOfType, regexes } from 'matches-shape';
const shape = new Shape([{
  name: string,
  age: number,
  birthDate: format(regexes.iso8601)
  friends: [string],
  gender: oneOf(['female', 'male']),
  random: oneOfType([number, string])
}]);
shape.matches([{
  name: 'John',
  age: 4,
  birthDate: '2012-04-03'
  friends: ['Sally', 5],
  gender: 'not-a-gender',
  random: {}
}])
// => false
shape.lastNonMatches();
// => ['Expected value at friends[1] to be a string, but found 5 (number).', 'Expected value at birthDate to be a string matching the given regex, but found "2012-04-03" (string)', 'Expected value at gender to be within the given array, but found "not-a-gender" (string)', 'Expected value at random to be one of the specified types, but found {} (object).']

Matching options

The following matchers can be imported destructured from matches-shape.

  • string - Asserts that the value is of type string.
  • number - Asserts that the value is of type number.
  • function - Asserts that the value is of type function.
  • boolean - Asserts that the value is of type boolean.
  • nul - Asserts that the value is null (a protected word, thus the weird spelling).
  • undef - Asserts that the value is of type undefined (a protected word, thus the weird spelling).
  • object - Asserts that the value is of type object (and NOT an array). Only to be used if you are ambivalent about the values within the object.
  • array - Asserts that the value is an array. Only to be used if you are ambivalent about the values within the array.
  • format(regex) - Asserts that the value matches the given regex.
  • oneOf([]) - Asserts that the value is within the specified options.
  • oneOfType([]) - Asserts that the value is one of the specified types.

Apart from these matchers, object shape is indicated by the shape object itself. In other words, the following shape object will assert that the object tested contains, under a "values" key, an array of objects with string values for their "type" key:

import Shape, { string } from 'matches-shape';

const shape = Shape.new({
    values: [{ type: string }]
});

One additional import is provided - regexes - which defines a handful of useful regex patterns for testing strings.

new Shape(format(regexes.iso8601)).matches('Some string')
# => false

Optional attributes

Sometimes you want to test that if an attribute exists, it is of a certain type -- but it doesn't need to exist. There are two options to achieve this. Either use the opt(matcher) function (ie { someKey: opt(string) }, or useoneOfType([]), with undef as one of the options:

import Shape, { undef, number, oneOfType } from 'matches-shape';

const shape  = new Shape({ optionalNumber: oneOfType([number, undef]) });
// Equivalent: new Shape({ optionalNumber: opt(number) });

shape.matches({ optionalNumber: 1 }) // => true
shape.matches({}) // => true
shape.matches({ optionalNumber: null }) // => false
shape.matches({ optionalNumber: '1' }) // => false

Printable Shape

Shape objects come with a printableShape attribute, which returns a version of the given shape with the expected values represented as type strings:

const shape = new Shape([{
  value: {
    anotherObject: {
      numberArray: [number],
      someValue: string,
      thisOneIsNull: nul,
      thisOneIsUndefined: undef,
      thisIsAFunction: func,
      thisIsFormatted: format(regexes.iso8601)
    }
  }
}]);

shape.printableShape
// Returns the below object
[{
  "value": {
    "anotherObject": {
      "numberArray": [
        "number"
      ],
      "someValue": "string",
      "thisOneIsNull": "null",
      "thisOneIsUndefined": "undefined",
      "thisIsAFunction": "function",
      "thisIsFormatted": "format"
    }
  }
}]

To pretty print a printableShape, just use JSON.stringify:

// The third argument specifies how many spaces to indent per nesting level
JSON.stringify(shape, null, 2);

TODO

  • [X] Improve error logging, so that errors point to particular nodes.
  • [X] Add a handful of basic regexes
  • [ ] Improve printableShape, so it (and errors) handle oneOf and oneOfType completely.