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 🙏

© 2025 – Pkg Stats / Ryan Hefner

object-prevent-setters

v1.0.1

Published

Prevent setters being invoked on an object.

Readme

Object_preventSetters

preventSetters() freezes an object (as per Object.freeze()) and additionally alters it so its setters throw.

import {preventSetters,areSettersBlocked} from "object-prevent-setters";  
  
const u = new URL( "https://example.com/index.html" );
preventSetters( u );
areSettersBlocked(u) === true;

u.protocol = "http:"; // ***THROWS****

Motivation

Modern javascript objects use setters (on the prototype) to define properties. So Object.freeze() is largely ineffectual:

const u = new URL( "https://example.com/" );
Object.freeze( u );     
u.protocol = "http:"; // This works!
u.toString() === "http://example.com/"

It's for this reason we have abominations like DOMRectReadOnly. Contrast this to, say, C++ where you can just do const URL url = new URL("https://example.com"); and know the URL is unwriteable.

preventSetters() takes a step towards this by re-writing the setters (including those on the prototype) so they honour a hidden flag on the object which blocks setting.

It's not perfect. But if a class's methods use its own setters, then you will get readonly protection:

import {preventSetters} from "object-prevent-setters";

class Pt {
  #x = 0;
  get x() { return this.#x }
  set x(value) { this.#x = value }
  
  translate( dx ) {
     // Note `this.x` and _not_ `this.#x`
     this.x += dx;
  }
}

const p = new Pt, q = new Pt;

Object.freeze(p);
p.translate( 1 ); 
p.x === 1;          

preventSetters( q );
q.translate( 1 ); //< **throws**

Installation

npm i object-prevent-setters

There's just a single file main.mjs which can be called from the browser. It exports two functions: preventSetters() and areSettersBlocked()

Usage

preventSetters(object)

  • object Anything.
  • Return: object

This takes an object and rewrites its own setters, and all the setters on its prototype chain, so that they throw when used on this object.

It then freezes the object (with Object.freeze()).

In common with Object.freeze(), non-object values are ignored. For convienece, object is returned.

areSettersBlocked(object)

  • object anything.
  • Return: boolean

Returns true iff preventSetters() has been called on the object. Non-objects return false.

Limitations and implementation details

  • This is trivial to break; for example:

         const date = new Date(0);
         assert.equal( date.getUTCHours(), 0 );
         preventSetters( date );
         assert.doesNotThrow( () => date.setUTCHours(1) );     
         assert.equal( date.getUTCHours(), 1 );

    (Issue: should we special case date to block this? Are there any other obvious classes where we might apply this?)

    But more subtle cases are possible. For example:

         const u = new URL( "https://example.com/index.html" );
         preventSetters( u );
         assert.throws( () => u.search = "?some=thing" );
         u.searchParams.append( "some", "thing" );
         assert.equal( u.toString(), "https://example.com/index.html?some=thing" );  
  • Setters can be inserted onto the object's prototype after preventSetters() has been called and they won't be blocked.

  • A private field is added to objects passed to preventSetters(), in addition to its setters being rewritten, and that changes the "shape" of the object - which will hurt performance in most engines. It means objects which have and haven't been through preventSetters() will have different "shapes" so there's concealed polymorphism.

  • The entire prototype chain of an object is monkey-patched with all the setters being rewritten, and each prototype object then has the private field added. Suffice to say, peformance will suffer. But if this proves popular, who knows TC39 may decide to implement it for real. ;)

My recommendation would be:

  1. Only use preventSetters() on your own classes.

  2. call preventSetters() immediately after the declaraion of a class; for example:

     class C {
        // ... 
     };
     preventSetters( new C );   

    This means the changes to the prototype happen before most classes are instanced. I might add a class decorator, once decorators become mainstream.

Changes

  • 1.0.1 Fixed some typos in README.md (the examples used the old repository name).