Polytype
Dynamic multiple inheritance for JavaScript and TypeScript. Without mixins.
Install / Use
/learn @fasttime/PolytypeREADME
Polytype · [![npm version][npm badge]][npm url]
Dynamic multiple inheritance for JavaScript and TypeScript. Without mixins.
Polytype is a library that adds support for dynamic multiple inheritance to JavaScript and TypeScript with a simple syntax. “Dynamic” means that changes to base classes at runtime are reflected immediately in all derived classes just as programmers would expect when working with single prototype inheritance.
Polytype runs in Node.js, Deno and in current versions of all major browsers.
Contents
Features
- Python style multiple inheritance
- Works in Node.js, Deno and in all new browsers
- Full TypeScript support
- Zero dependencies
- Access to all inherited base class features
- constructors
- methods, getters and setters, class fields
- value properties on base classes and base instance prototypes
in,instanceofandisPrototypeOfintegration
Setup Instructions
Polytytpe is available in two flavors: a module build (comprising CommonJS and ECMAScript modules) with exported definitions and a script build where all definitions are accessible through global objects. Apart from this, both builds provide the same features and are available in the standard package.
In Node.js
If you are using Node.js, you can install Polytype with npm.
npm install polytype
Then you can import it in your code like any module.
const { classes } = require("polytype"); // CommonJS syntax
or
import { classes } from "polytype"; // ECMAScript module syntax
Alternatively, you can import the script build at the start of your application and access Polytype definitions through global objects.
require("polytype/global"); // CommonJS syntax
or
import "polytype/global"; // ECMAScript module syntax
In Deno
You can import the module or script build of Polytype from a CDN of your choice, e.g.
import { classes } from "https://esm.sh/polytype"; // Module build
or
import "https://esm.sh/polytype/global"; // Script build
In the browser
In an HTML‐based application, the script build of Polytype can be simply embedded. Just download polytype.min.js and include it in your HTML file.
<script src="polytype.min.js"></script>
Alternatively, you can hotlink the script from the latest release package using a CDN of your choice.
<script src="https://cdn.jsdelivr.net/npm/polytype@0.17.0/lib/polytype.min.js"></script>
If your browser application already uses ECMAScript modules, you can also import the module build
(“.mjs”) in contexts where Polytype specific definitions like classes are required.
This has the advantage to avoid possible naming conflicts on global objects.
import { classes } from "https://cdn.jsdelivr.net/npm/polytype@0.17.0/lib/polytype.min.mjs";
Usage
Inheriting from multiple base classes
For example, declare a derived class ColoredCircle that inherits from both base classes Circle
and ColoredObject.
class Circle
{
constructor(centerX, centerY, radius = 1)
{
this.moveTo(centerX, centerY);
this.radius = radius;
}
get diameter() { return this.radius * 2; }
set diameter(diameter) { this.radius = diameter / 2; }
moveTo(centerX, centerY)
{
this.centerX = centerX;
this.centerY = centerY;
}
reset()
{
this.moveTo(0, 0);
this.radius = 1;
}
toString()
{
return `circle with center (${this.centerX}, ${this.centerY}) and radius ${this.radius}`;
}
}
class ColoredObject
{
constructor(color) { this.color = color; }
static areSameColor(obj1, obj2) { return obj1.color === obj2.color; }
paint() { console.log(`painting in ${this.color}`); }
reset() { this.color = "white"; }
toString() { return `${this.color} object`; }
}
class ColoredCircle
extends classes(Circle, ColoredObject) // Base classes as comma‐separated params
{
// Add methods here.
}
Using methods and properties from multiple base classes
const c = new ColoredCircle();
c.moveTo(42, 31);
c.radius = 2;
c.color = "red";
console.log(c.centerX, c.centerY); // 42, 31
console.log(c.diameter); // 4
c.paint(); // "painting in red"
As usual, the keyword super invokes a base class method or property accessor when used inside a
derived class.
class ColoredCircle
extends classes(Circle, ColoredObject)
{
paint()
{
super.paint(); // Using method paint from some base class
}
}
If different base classes include a member with the same name, the syntax
super.class(DirectBaseClass).member
can be used to make the member access unambiguous.
class ColoredCircle
extends classes(Circle, ColoredObject)
{
toString()
{
// Using method toString from base class Circle
const circleString = super.class(Circle).toString();
return `${circleString} in ${this.color}`;
}
}
More generally, super.class(DirectBaseClass)[propertyKey] can be used to reference a (possibly
inherited) property of a particular direct base class in the body of a derived class.
Note: In TypeScript, the syntax described here cannot be used to access protected instance members, so it is currently not possible to disambiguate between protected instance members having the same name, the same index or the same symbol in different base classes.
Static methods and properties
Static methods and property accessors are inherited, too.
ColoredCircle.areSameColor(c1, c2)
same as
ColoredObject.areSameColor(c1, c2)
Invoking multiple base constructors
In the constructor of a derived class, use arrays to group together parameters to be passed to the constructors of each direct base class.
class ColoredCircle
extends classes(Circle, ColoredObject)
{
constructor(centerX, centerY, radius, color)
{
super
(
[centerX, centerY, radius], // Circle constructor params
[color] // ColoredObject constructor params
);
}
}
If you prefer to keep parameter lists associated to their base classes explicitly without relying on order, there is an alternative syntax.
class GreenCircle
extends classes(Circle, ColoredObject)
{
constructor(centerX, centerY, radius)
{
super
(
{ super: ColoredObject, arguments: ["green"] },
{ super: Circle, arguments: [centerX, centerY, radius] }
);
}
}
There is no need to specify an array of parameters for each direct base constructor. If the parameter arrays are omitted, the base constructors will still be invoked without parameters.
class WhiteUnitCircle
extends classes(Circle, ColoredObject)
{
constructor()
{
super(); // Base constructors invoked without parameters
this.centerX = 0;
this.centerY = 0;
// The radius has been already set to 1 by the Circle constructor.
this.color = "white";
}
}
instanceof
The instanceof operator works just as it should.
const c = new ColoredCircle();
console.log(c instanceof Circle); // true
console.log(c instanceof ColoredObject); // true
console.log(c instanceof ColoredCircle); // true
console.log(c instanceof Object); // true
console.log(c instanceof Array); // false
In pure JavaScript, the expression
B.prototype instanceof A
determines if A is a base class of class B.
Polytype takes care that this test still works well with multiple inheritance.
console.log(ColoredCircle.prototype instanceof Circle); // true
console.log(ColoredCircle.prototype instanceof ColoredObject); // true
console.log(ColoredCircle.prototype instanceof ColoredCircle); // false
console.log(ColoredCircle.prototype instanceof Object); // true
console.log(Circle.prototype instanceof ColoredObject); // false
in
The in operator determines whether a property is in an object or in its prototype chain.
In the case of multiple inheritance, the prototype “chain” looks more like a directed graph, yet the
function of the in operator is the same.
const c = new ColoredCircle();
console.log("moveTo" in c); // true
console.log("paint" in c); // true
console.log("areSameColor" in Colored
Related Skills
node-connect
347.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
