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

protypes

v1.1.0

Published

Joins Multiple Implementations Into A Single Class.

Readme

Protypes

by Art Deco™Professional Software Development Company In London.

npm version

PLEASE REFER TO THE FULL DOCUMENTATION ON THE PROTYPES HOMEPAGE! Information provided in this README has illustrative purpose only, is limited and doesn't describe API of this library in details.

protypes is: Joins Multiple Implementations Into A Single Class.

yarn add protypes
npm i protypes

Table of Contents

What Is Protype?

JavaScript is prototype-based language. Prototypes are objects from which other objects are created, for example, using Object.create(). Since introduction of classes in ES5 standard, the programming was largely class-based, however there's another possibility: via protypes.

A protype is the type of prototypes. It's like a class but simpler, denoted in a standard object. Class-based approach is really a syntactic sugar over prototypes. There are limitations to the standard hierarchical model, such that larger systems can not be adequately expressed in terms of gradually refining implementations of specialising interfaces, and types need to be subtyped via alternative routes, that is, protypes, which simply allow to copy methods into objects without vertical inheritance.

// Standard class-based model:

class Doer {
  do() {
    console.log('doing work')
  }
}
class Writer {
  write() {
    console.log('hello world')
  }
}

// `MyClass` can inherit from `Doer`, but
// how can we make it extend `Writer`, too?
class MyClass extends Doer {}

// Absence of multiple inheritance
// is a limitation of JavaScript
// solved by *Protypes*.

There's no support for multiple inheritance in JS, so the code reuse for types that specialise in multiple things isn't possible without a dynamic solution such that is provided by this library. Protypes allows to subtype types from their supertypes, i.e. to inherit methods horizontally rather than vertically:

import { subtype } from '../..'

const Doer = {        // <- protype
  do() {
    console.log('doing work')
  },
}
const Writer = {      // <- protype
  write() {
    console.log('hello world')
  },
}
class MyClass {} // <- target class

subtype(MyClass, null, Doer, Writer)
const c = new MyClass()
c.do()
c.write()
doing work
hello world

As you can see, protypes is a more natural approach to prototype-based programming that is facilitated by JavaScript. Only because of the lack of theoretical background in programming and the mainstream approach to development that involves classes, they've been used very rarely. But once you discover their utility, you will fully realise their potential. Plus, nobody is taking classes away, and protypes can be mixed in any class with its hierarchical inheritance structure. When it becomes illogical to work "in depth", then protypes with their "in width" approach will come to the rescue.

API

The package is available by importing its named functions and symbols:

import { subtype, is, $name } from 'protypes'

They are briefly described on this page, but the full description is found in the official documentation.

subtype(Target, opts, ...(Protype|Class))

Subtyping is a feature of OOP which allows objects of one type to be accepted in contexts expecting another type (class) [Sny86]. If you ever used down-casting, you were using this feature. It is also the basis for polymorphism. Just see the example below to immediately understand what subtyping is:

class Doer {
  do() {
    console.log('doing work')
  }
}
class MyClass extends Doer {}

/**
 * The main function.
 * @param {Doer} doer
 */
function main(doer) {
  doer.do()
}

const c = new MyClass()

main(c)

We defined a class, Doer, and implemented the do method in it. We also declared a function main that accepts a Doer as its argument. We then proceed to create a new instance of a MyClass which extends the Doer class. And although the function main receives this instance, it's still type-sound since the instance is a subtype of Doer (which is a supertype of MyClass). This is what subtyping is.

doing work

When we want to extend classes with protypes (or other classes), we're subtyping the target class by those protypes (or classes). In formal notation, it would be written as Target <: Protype (Subtype <: Supertype). The target can thus become a subtype of any number of other types. Objects created via such class constructor, will inherit all methods from all its supertypes. Inheritance doesn't necessary mean standard top-down sharing of methods via the extends keyword, but can also mean horizontal borrowing of methods from protypes.

import { subtype } from 'protypes'

class Doer {
  do() {
    this._isDoing = true
    console.log('doing work')
  }
  get isDoing() {
    return this._isDoing
  }
}
const Writer = {
  what: 'world',
  write() {
    console.log('hello %s', this.what)
  },
}
class MyClass {} // <- target class

subtype(MyClass, null, Doer, Writer)
const c = new MyClass()
c.do()
c.what = 'WORLD'
c.write()
console.log('is doing: %s', c.isDoing)
doing work
hello WORLD
is doing: true

The subtype accepts the target class as the first argument, some options (if no options are required, null needs to be passed), and then the list of all protypes and classes that need to be subtyped. Their methods, getters, setters and even static data fields will be copied across.

There are some nuances that need to be considered, such as using super keyword, which is actually statically bound to the prototype's instance, and merging getters and setters. You can follow the links to read about these intricacies on the package's documentation website.

Options

The list of options that can be used with the subtype method includes:

import { subtype } from 'protypes'

class Parent {
  method() {
    console.log('parent method')
  }
}
class Target extends Parent {}
let Protype = {
  run() {
    super.method()
  },
}
subtype(Target, null, Protype)
let t = new Target()
try {
  t.run()
} catch (err) {
  console.log(err.message)
}
// fix super
class Target2 extends Parent {}
subtype(Target2, {
  setProtypesPrototype: true,
}, Protype)
t = new Target2()
t.run()
(intermediate value).method is not a function
parent method
import { subtype } from 'protypes'

class Target {}
let Protype = {
  run(arg) {
    console.log('running protype with %s', arg)
  },
}
const decorator = (method, propName) => {
  return function(...args) {
    console.log('pre-condition on %s', propName)
    const res = method.call(this, ...args)
    console.log('post-condition on %s', propName)
    return res
  }
}
subtype(Target, {
  methodDecorators: [decorator],
}, Protype)
const t = new Target()
t.run('hello')
pre-condition on run
running protype with hello
post-condition on run
import { subtype } from 'protypes'

class Target {
  set example(e) {
    this._e = e
  }
}

let Protype = {
  get example() {
    return this._e
  },
}

subtype(Target, null, Protype)
let t = new Target()
t.example = 'example'



// expect undefined
console.log(t.example)
undefined
import { subtype } from 'protypes'

class Target2 {
  set example(e) {
    this._e = e
  }
}

let Protype = {
  get example() {
    return this._e
  },
}

subtype(Target2, {
  mergeGettersSetters: true,
}, Protype)
let t2 = new Target2()
t2.example = 'example'

// expect "example"
console.log(t2.example)
example
import { subtype } from 'protypes'

class Parent {
  get example() {
    return this._e
  }
}
class Target extends Parent{
  set example(e) {
    this._e = e
  }
}

subtype(Target, null)
let t = new Target()
t.example = 'example'
console.log(t.example)
undefined
import { subtype } from 'protypes'

class Parent {
  get example() {
    return this._e
  }
}
class Target extends Parent{
  set example(e) {
    this._e = e
  }
}

subtype(Target, {
  fixTargetGettersSetters: true,
})
let t = new Target()
t.example = 'example'
console.log(t.example)
example
import { subtype } from 'protypes'

class Target {
  get target() { return 'target' }
  test() { console.log('test:', this.target) }
}

subtype(Target, {
  bindings: {
    bindMethods: true,
  },
}, {
  get protype() { return 'protype' },
  example() { console.log('example: %s, %s',
    this.protype, this.target) },
})

let t = new Target()
const { example, test } = t
test()
example()
test: target
example: protype, target

is(obj, protypeName)

To determine whether the given instance's class is Proto|Class or a subclass of Proto|Class. In plain JS, we'd use instanceof however with multiple inheritance / subtyping this does not work as the methods are copied across into the target class. The is method from this library can be used to determine whether a Protype (or Class) has been implemented by the given object.

import {
  subtype, $name, is,
} from 'protypes'

class Doer {
  get [$name]() { return 'Doer' }
}
const Writer = {
  [$name]: 'Writer',
}
class MyClass {} // <- target class

subtype(MyClass, null, Doer, Writer)
const c = new MyClass()
console.log('is Writer:',
  is(c, 'Writer'))
console.log('is Doer:',
  is(c, 'Doer'))
console.log('is Member:',
  is(c, 'Member'))
is Writer: true
is Doer: true
is Member: false

The check is performed on strings currently, but in the future version it'll be extended to passing of actual protypes. The reason for this limitation is that with non-string based implementation of the is method, chances are high you might run into circular dependencies that would break the system. The name must be defined on protypes and classes using the special $name symbol exported by the library.

Copyright & License

The public free version of the package is provided under the GNU Affero General Public License v3.0 so that you can use it in AGPL-compatible projects. The full version requires purchasing of a license key and is distributed under an EULA terms. Please contact Art Deco on Keybase chat to purchase the key.