Berrigan Berrigan - 3 years ago 145
Javascript Question

Creating multiple abstract classes javascript ES6

Today I came up with an idea, to use Proxy object, to allow creation of multiple abstract classes, for example

const abstract = abstractClass => new Proxy(abstractClass,{
construct: (target, args) => { throw new Error('Error, class was declared as abstract!') }
});

class A{}
class B{}
class C{}
[A,B,C] = [A,B,C].map(c => abstract(c));


So my question is whether this solution has any drawbacks, and if so, what they are.

Answer Source

The drawback is that Proxy cannot be reliably polyfilled in ES5 and it is slow.

A good recipe is to solve this with inheritance:

class Abstract {
    constructor() {
        if (Object.getPrototypeOf(this.constructor) === Abstract
            || this.constructor === Abstract) {
            throw new Error("Cannot instantiate abstract class");
        }
    }
};

class AbstractFoo extends Abstract {...}

class ConcreteFoo extends AbstractFoo {...}

Abstract and AbstractFoo will throw an error when instantiated directly.

ES.next decorators can be used to make the task easier:

function abstract(target) {
    return class Abstract extends target {
        constructor(...args) {
            super(...args);
            if (this.constructor === Abstract) {
                throw new Error("Cannot instantiate abstract class");
            }
        }
    };
}
@abstract
class AbstractFoo {...}

class ConcreteFoo extends AbstractFoo {...}

Since decorators are basically helper functions, they can be applied directly in plain ES6:

const AbstractFoo = abstract(class AbstractFoo {...});

class ConcreteFoo extends AbstractFoo {...}

Notice that in the case of a decorator original constructor will be evaluated before throwing an error, this is the price of using extends. The workaround is to use a function instead of class and inherit it from target manually, similarly to TypeScript __extends and Babel __inherits helper functions, this way an error could be thrown before super().

A cleaner way is to use TypeScript (as it was suggested in comments), it introduces abstract classes as language feature and takes care of it at design time. This allows to not pollute prototype chain.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download