Make programming easier

Introduction
Is `instanceof` broken?

Is `instanceof` broken?

We all know what instanceof does. By definition

The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value.
From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof


Few examples:

class Foo {
	constructor() {
		this.property = 'test';
	}	
}


new Foo() instanceof Foo; // true
{property: 'test'} instanceof Foo; // false

Very simple and clear. But as always in reality

When I was developing @pallad/secret and @pallad/config i found that CLI for config didn't handle instances of Secret and couldn't detect instances of Provider . Both of those classes uses instanceof for type check, which seamed to be great option.

The issue was that those modules were installed more than one time on my system. One was global installation and second local from examples folder. Creating an instance from local module does not work properly with instanceof operator within a global module. Who would have thought?

I'm not alone in that problem. The chance of receiving multiple installations of the same module in the project is quite high. Take a look at npm list in some of your projects to see that.

The fix? Just define extra unique non-configurable and non-enumerable property in your object.

const TYPE_KEY = '@type';
const TYPE = '@mylib/name/Foo';

class Foo {

    constructor() {
        Object.defineProperty(this, TYPE_KEY, {
            value: TYPE,
            configurable: false,
            enumerable: false
        });
    }

    static is(value: any): value is Foo {
        return value instanceof Foo ||
            typeof value === 'object' && value !== null &&
            value[TYPE_KEY] === TYPE
    }
}

You can always use predicates to simplify that

import * as is from 'predicates';

const TYPE_KEY = '@type';
const TYPE = '@mylib/name/Foo';

const IS_TYPE = is.property(TYPE_KEY, is.strictEqual(TYPE));

class Foo {

    constructor() {
        Object.defineProperty(this, TYPE_KEY, {
            value: TYPE,
            configurable: false,
            enumerable: false
        });
    }

    static is(value: any): value is Foo {
        return value instanceof Foo || IS_TYPE(value);
    }
}

Is instanceof bad then?

Absolutely not! It is a great tool for its job. When working on local project where all modules are guaranteed to be installed once in the system or in the project then it is completely fine. However when developing a library that is suppose to be used my many people in various places it is worth to think about it.

Author

wookieb

Fullstack developer with 10 years of experience. Passionated about programming, computers and how things work.

View Comments
Previous Post

Documenting my work - part 1