
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Operator overloading is a common programming feature that JavaScript lacks. Just something as simple as adding two vectors requires a .add() method or element-by-element assignment.
boperators brings operator overloading to JavaScript by leveraging TypeScript typings. You define overloaded methods on a class for whichever operators you want, and at build time we find every usage of those operators and substitute in your method calls.
This is the core library and API, and isn't designed to be used directly. Instead, you can use:
tsc plugin;We also offer a TypeScript Language Server plugin for real-time type hinting and intellisense in your IDE, and an MCP server to optimize your vibe coding experience.
npm install -D boperators @boperators/cli @boperators/plugin-ts-language-server
Operator overloads are standard TypeScript methods whose name is the operator string. Both string literal names and computed bracket names are supported — they are equivalent:
class Vec2 {
// String literal name
static "+"(a: Vec2, b: Vec2): Vec2 { ... }
// Computed bracket name — identical behaviour
static ["+"](a: Vec2, b: Vec2): Vec2 { ... }
}
Use whichever style you prefer. The examples below use the bracket style.
Static operators (+, -, *, /, %, comparisons, logical) are static methods with two parameters (LHS and RHS). At least one parameter must match the class type.
class Vector3 {
static ["+"](a: Vector3, b: Vector3): Vector3 {
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
// Multiple overloads for different RHS types — use TypeScript overload signatures,
// then handle all cases in a single implementation.
static ["*"](a: Vector3, b: Vector3): Vector3;
static ["*"](a: Vector3, b: number): Vector3;
static ["*"](a: Vector3, b: Vector3 | number): Vector3 {
if (b instanceof Vector3) {
return new Vector3(
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x,
);
}
return new Vector3(a.x * b, a.y * b, a.z * b);
}
// Comparison operators must return boolean
static ["=="](a: Vector3, b: Vector3): boolean {
return a.length() === b.length();
}
}
Instance operators (+=, -=, *=, /=, %=, &&=, ||=) are instance methods with a single parameter (the RHS). They use this for the LHS and must return void.
class Vector3 {
["+="](rhs: Vector3): void {
this.x += rhs.x;
this.y += rhs.y;
this.z += rhs.z;
}
}
Unlike with JavaScript primitives, you can declare a variable as const and still use assignment operators with it, since they only mutate the object.
const vec3 = new Vector3(3, 4, 5);
vec3 += new Vector3(6, 7, 8);
Prefix unary operators (-, +, !, ~) are static methods with a single parameter matching the class type.
For operators that also have a binary form (-, +), both can live on the same method — just add overload signatures for each, distinguished by parameter count. The implementation then handles all cases.
class Vector3 {
// Unary-only operator
static ["!"](a: Vector3): boolean {
return a.x === 0 && a.y === 0 && a.z === 0;
}
// Combined binary + unary on the same operator
static ["-"](a: Vector3, b: Vector3): Vector3;
static ["-"](a: Vector3): Vector3;
static ["-"](a: Vector3, b?: Vector3): Vector3 {
if (b) return new Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
return new Vector3(-a.x, -a.y, -a.z);
}
}
Postfix unary operators (++, --) are instance methods with no parameters. They mutate the object via this and must return void.
class Counter {
value = 0;
["++"](): void {
this.value++;
}
}
The transform only applies to consuming code, not to the overload definitions themselves. If you need to call an overloaded operator inside an overload body, call the method directly:
class Expr {
static ["-"](inner: Expr): Expr;
static ["-"](lhs: Expr, rhs: Expr): Expr;
static ["-"](lhs: Expr, rhs: number): Expr;
static ["-"](lhs: number, rhs: Expr): Expr;
static ["-"](lhs: Expr | number, rhs?: Expr | number): Expr {
if (rhs === undefined) return new Expr.Neg(lhs as Expr);
// Call the overload methods directly — don't use operator syntax here,
// as the source transform has not yet run on this code.
const l = typeof lhs === "number" ? new Expr.Num(lhs) : lhs;
const r = typeof rhs === "number" ? Expr["-"](new Expr.Num(rhs)) : Expr["-"](rhs);
return Expr["+"](l, r);
}
}
boperators has a two-phase pipeline:
OverloadStore scans all source files for classes with operator-named methods and indexes them by (operatorKind, lhsType, rhsType).OverloadInjector finds binary and unary expressions, looks up matching overloads, and replaces them:
a + b becomes Vector3["+"](a, b)a += b becomes a["+="](b)-a becomes Vector3["-"](a)x++ becomes x["++"]( )Imports for referenced classes are automatically added where needed.
| Operator | Type | Notes |
|---|---|---|
+ | static | |
- | static | |
* | static | |
/ | static | |
% | static | |
+= | instance | Must return void |
-= | instance | Must return void |
*= | instance | Must return void |
/= | instance | Must return void |
%= | instance | Must return void |
> | static | Must return boolean |
>= | static | Must return boolean |
< | static | Must return boolean |
<= | static | Must return boolean |
== | static | Must return boolean |
=== | static | Must return boolean |
!= | static | Must return boolean |
!== | static | Must return boolean |
&& | static | |
|| | static | |
?? | static | |
&&= | instance | Must return void |
||= | instance | Must return void |
- (unary) | static | Prefix negation (1 param) |
+ (unary) | static | Prefix plus (1 param) |
! | static | Prefix logical NOT (1 param) |
~ | static | Prefix bitwise NOT (1 param) |
++ | instance | Postfix increment, must return void |
-- | instance | Postfix decrement, must return void |
When parsing overload definitions, if there are duplicate overloads with matching (operator, lhsType, rhsType), a warning is shown (or an error if --error-on-warning is set via the CLI).
MIT
FAQs
Operator overloading for TypeScript.
We found that boperators demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.