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

boperators

v0.3.2

Published

Operator overloading for TypeScript.

Downloads

80

Readme

boperators

Operator overloading for JavaScript and TypeScript.

Sym.JS logo

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:

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.

Installation

npm install -D boperators @boperators/cli @boperators/plugin-ts-language-server

Defining Overloads

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

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

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

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

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++;
    }
}

Using Overloaded Operators Within Definitions

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);
    }
}

How It Works

boperators has a two-phase pipeline:

  1. Parse: OverloadStore scans all source files for classes with operator-named methods and indexes them by (operatorKind, lhsType, rhsType).
  2. Transform: OverloadInjector finds binary and unary expressions, looks up matching overloads, and replaces them:
    • Binary static: a + b becomes Vector3["+"](a, b)
    • Instance compound: a += b becomes a["+="](b)
    • Prefix unary: -a becomes Vector3["-"](a)
    • Postfix unary: x++ becomes x["++"]( )

Imports for referenced classes are automatically added where needed.

Supported Operators

| 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 |

Conflict Detection

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).

License

MIT