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 🙏

© 2024 – Pkg Stats / Ryan Hefner

private-decorator

v0.1.7

Published

Private and protected members in JavaScript!

Downloads

3

Readme

@privateMember and @protectedMember decorators!

Have you ever dreamt about true privates in JS? I did not :wink:

But when a friend was laughing at JS saying that the new ES6 class inheritance is useless without private/protected and seems that there is still no easy way to achieve that - I just said "challenge accepted" :bowtie:

But seriously, it started with a proof of concept and ended with a full private/protected class enhancement solution via decorators.

What is notable is that this package has zero dependencies. Also making this was a lot of low level JS fun :wink:

Why not @private/@protected?

Believe me or not - private and protected are keywords (reserved words) in JavaScript so I decided not to conflict with them even though those keywords mean nothing now.

How to use it?

npm install private-decorator babel-plugin-transform-decorators-legacy babel-preset-es2015-without-strict babel-preset-stage-1 --save-dev

In your .babelrc you need to have 3 things:

{
  "presets": ["es2015-without-strict", "stage-1"],
  "plugins": [
    "transform-decorators-legacy"
  ]
}
  1. es2015-without-strict preset.
  2. stage-1 preset.
  3. transform-decorators-legacy plugin enabled.

In Node 4/5/6 if you will use babel-preset-es2015-node(4/5/6) this package will not work. Classes are supported natively since node 4 and they are in strict mode by default.

Why?

Before you will actually use it, think thoroughly if you really need this. Standard techniques for making things private in JS exists and now with Symbols it is pretty easy.

Besides the normal benefits of private/protected types in class inheritance the main reason this package was created was to eliminate 'unsupported' usage of libraries. Many times instead of reporting an issue or PR, developers were making workarounds and often use some internals of the library directly.

It is not a good way to go, as later when the library is updated, often it breaks the workarounds. Of course we usually do not care unless we are supporting those developers and helping them makes our time going to waste.

If you are convinced to try this, be aware that using this solution comes with a significant cost (see below).

The cost

  1. The whole solution is based on Function.caller use which is prohibited in strict mode - therefore strict mode must be disabled.
  2. At every call to a private prop/get/set/method some CPU is needed to determine whether the call is valid. It is cached wherever it is possible, but I would advise not to use it where performance matters. The least efficient use case is accessing anything private/protected from setters/getters as it requires a lot of computation and memory to check if a getter belongs to a class and therefore has access to the guarded class member.
  3. Probably not all use cases are supported - if you run into problems, check if your case is in the test scenarios.

Usage:

Both @privateMember and @protectedMember works with properties, getters, setters and methods.

import { privateMember, protectedMember } from 'private-decorator';

class Foo {
   
       @privateMember
       privatePropertyWithDefault = 'test';
   
       @privateMember
       privateProperty;
   
       @privateMember
       get privateGetter() {
           return this.privateProperty;
       }
   
       @privateMember
       set privateSetter(value) {
           this.privateProperty = value;
       }
       
       @privateMember
       privateMethod() {
       
       }
}

Usage in functions/callbacks

Normally this will fail:

import { privateMember, protectedMember } from 'private-decorator';
class Test {

    @privateMember
    privateProperty;

    publicMethod() {
        [1, 2, 3].forEach((value) => {
            this.privateProperty += value;
        });
    }
}

since any function declared (arrow or normal does not matter) inside a method scope is not bound to the class. A call to something private from it is always detected as invalid since function does not belong to the class. You can not get this work simply using bind as this intentionally will not work. To make such things possible I have created a ScopedCallbacks abstract class which gives you a _ helper method.

import { privateMember, protectedMember, ScopedCallbacks } from 'private-decorator'; 

class Test extends ScopedCallbacks {

    @privateMember
    privateProperty;

    publicMethod() {
        [1, 2, 3].forEach(this._((value) => {
            this.privateProperty += value;
        }));
    }
}

As you can see the arrow function is now wrapped in this._ method which makes it work.

A word on the implementation

Instead of making a global container for the privates, this solution tries to keep all the data in the class instance itself. It also does not make properties under Symbol but instead it creates a private getters and setter for every decorated property. Be aware that even debuggers will not be able to access private properties, you will have to dig hard to reach for the value. I have resigned of making shadow/proxy class with just the public members as I ran into many inheritance related problems.

Tests

Run npm run test or gulp test. There is also gulp watch available.

Contribution

PRs are always welcome. Be sure to update/check the tests. I encourage you to use gulp watch while developing.