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 🙏

© 2026 – Pkg Stats / Ryan Hefner

isotropic-instance-of

v0.1.0

Published

A mixin aware instanceof

Readme

isotropic-instance-of

npm version License

An instanceof check that understands mixins.

Why Use This?

  • Recognizes Mixins: The native instanceof operator can't see them
  • A Superset of instanceof: Anything instanceof reports as true is reported as true here, so it's a safe substitute
  • Follows Mixin Ancestry: A mixin's superclasses and a mixin's own mixins are all recognized
  • Familiar Signature: Two arguments in the same order as the operator's operands
  • Structured Errors: An invalid constructor throws an isotropic-error named TypeError

The Problem

isotropic-make implements mixins by copying the mixin's prototype properties onto the new class's prototype rather than by linking prototypes. That is what makes multiple mixins possible, but it means a mixin never appears in an instance's prototype chain, and instanceof only looks at the prototype chain.

import _make from 'isotropic-make';

const _Serializable = _make('Serializable', {
        serialize () {
            return JSON.stringify(this);
        }
    }),
    _Model = _make('Model', [
        _Serializable
    ], {});

{
    const model = _Model();

    console.log(typeof model.serialize); // function
    console.log(model instanceof _Serializable); // false
}

The object has everything the mixin provides, but the operator says it is not an instance of it. This module answers the question the operator was meant to answer.

import _instanceOf from 'isotropic-instance-of';

console.log(_instanceOf(model, _Serializable)); // true

Installation

npm install isotropic-instance-of

Usage

The arguments are in the same order as the operands of instanceof.

import _instanceOf from 'isotropic-instance-of';

if (_instanceOf(value, _Model)) {
    // value is a Model, or has Model mixed in
}

What Counts as an Instance

instanceOf(instance, ConstructorFunction) returns true when any of the following is true:

  • instance instanceof ConstructorFunction is true, including through a custom Symbol.hasInstance method
  • ConstructorFunction is mixed into the instance's class
  • ConstructorFunction is mixed into any class in the instance's prototype chain
  • ConstructorFunction is an ancestor of one of those mixins
  • ConstructorFunction is mixed into one of those mixins, to any depth
import _instanceOf from 'isotropic-instance-of';
import _make from 'isotropic-make';

const _Base = _make('Base', {}),
    _MixinBase = _make('MixinBase', {}),
    _NestedMixin = _make('NestedMixin', {}),

    _Mixin = _make('Mixin', _MixinBase, [
        _NestedMixin
    ], {}),

    _Model = _make('Model', _Base, [
        _Mixin
    ], {}),

    _SubModel = _make('SubModel', _Model, {});

{
    const subModel = _SubModel();

    console.log(_instanceOf(subModel, _SubModel)); // true, its own class
    console.log(_instanceOf(subModel, _Model)); // true, an ancestor class
    console.log(_instanceOf(subModel, _Base)); // true, an ancestor class
    console.log(_instanceOf(subModel, _Mixin)); // true, mixed into an ancestor
    console.log(_instanceOf(subModel, _MixinBase)); // true, an ancestor of that mixin
    console.log(_instanceOf(subModel, _NestedMixin)); // true, mixed into that mixin
}

Traversal is handled by isotropic-mixin-prototype-chain.

Compatibility with instanceof

The result is a superset of the operator's, so replacing instanceof with this function never turns a true into a false.

console.log(_instanceOf({}, Object)); // true
console.log(_instanceOf([], Array)); // true
console.log(_instanceOf([], Object)); // true
console.log(_instanceOf(new Map(), Map)); // true
console.log(_instanceOf(() => null, Function)); // true

Native classes behave exactly as they do with the operator, because there are no mixins to find.

class Collection extends Array {
}

console.log(_instanceOf(new Collection(), Array)); // true
console.log(_instanceOf([], Collection)); // false

Primitives, null, and undefined return false, and never throw.

console.log(_instanceOf(null, Object)); // false
console.log(_instanceOf(void null, Object)); // false
console.log(_instanceOf(1, Number)); // false
console.log(_instanceOf('string', String)); // false
console.log(_instanceOf(Object.create(null), Object)); // false

Compatibility with Symbol.hasInstance

A custom Symbol.hasInstance method is honored when it returns true.

class Magic {
    static [Symbol.hasInstance] (value) {
        return value === 'magic';
    }
}

console.log(_instanceOf('magic', Magic)); // true

When a custom Symbol.hasInstance method returns false, this package continues searching the prototype chain and may return true anyway. This package exists to answer a broader question than the language’s instanceof: "Is this constructor somewhere in the full prototype chain, including mixins?" A custom Symbol.hasInstance method that deliberately returns false is expressing an opinion about the narrower language operator. It can't answer the broader question this utility is designed to answer.

Errors

Where the operator throws a native TypeError, this function throws an isotropic-error named TypeError, with the arguments in details.

A ConstructorFunction that is not a function:

_instanceOf({}, 'Model');
// TypeError: ConstructorFunction must be a function

A ConstructorFunction that has no prototype object and no custom Symbol.hasInstance method, such as an arrow function or a concise method:

_instanceOf({}, () => null);
// TypeError: ConstructorFunction must have a prototype object

Both carry details.ConstructorFunction and details.instance, so the offending arguments are in the report.

try {
    _instanceOf(value, notAConstructor);
} catch (error) {
    console.log(error.name); // TypeError
    console.log(error.details.ConstructorFunction);
}

Only the ConstructorFunction is validated. Any value at all is acceptable as the instance.

API Reference

instanceOf(instance, ConstructorFunction)

| Parameter | Type | Description | | --- | --- | --- | | instance | Any | The value to test | | ConstructorFunction | Function | The constructor to test against |

Returns a boolean. Throws an isotropic-error named TypeError when ConstructorFunction cannot be used as the right operand of instanceof.

Examples

Validating an Argument

import _Error from 'isotropic-error';
import _instanceOf from 'isotropic-instance-of';

const connect = ({
    transport
}) => {
    if (!_instanceOf(transport, _Transport)) {
        throw _Error({
            details: {
                transport
            },
            message: 'transport must be a Transport'
        });
    }

    // ...
};

This accepts a class that mixes in _Transport as readily as one that extends it, which is usually what a caller expects when a library documents a capability rather than a base class.

Dispatching on Capability

const render = value => {
    if (_instanceOf(value, _Renderable)) {
        return value.render();
    }

    if (_instanceOf(value, _Serializable)) {
        return value.serialize();
    }

    return String(value);
};

_Renderable and _Serializable are mixins, so no class needs to inherit from either one to participate.

Filtering a Collection

const widgets = children.filter(child => _instanceOf(child, _Widget));

Notes

Mixins Are Found Through the Class, Not the Object

The mixins recognized are the ones declared when the classes were made. Copying a mixin's methods onto an object by hand does not make that object an instance of the mixin.

The Prototype Chain Is Walked From the Instance's Prototype

An object is not an instance of a constructor merely because it is that constructor's prototype, which matches the operator.

console.log(_instanceOf(_Model.prototype, _Model)); // false
console.log(_instanceOf(Object.create(_Model.prototype), _Model)); // true

Cost

The operator is a single prototype chain walk. This function does that first and only walks mixins when the operator says no, so the common true case is no slower than instanceof. A negative result walks the full mixin graph, which is proportional to the number of classes and mixins involved. Where a check is on a hot path and the classes involved have no mixins, instanceof is still the cheaper tool.

Integration with Other Isotropic Modules

  • isotropic-make: Creates the classes and mixins this recognizes
  • isotropic-mixin-prototype-chain: Walks the prototype chain of an object and its mixins
  • isotropic-error: Produces the structured TypeError

Contributing

Please refer to CONTRIBUTING.md for information on how to contribute.

Issues

Please refer to the issue tracker.

License

BSD-3-Clause