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

instance-decorators

v1.1.4

Published

this library allows you to create decorators that only run when the class is initialized

Downloads

6

Readme

Instance Decorators (npm | git)

Note: the git version has the lastest corrections to this file.

This npm library enables users to create decorators that run when the class constructs.

$ npm install instance-decorators

Pages (or skip)

Some use cases

There are a huge range of applicable reasons and places where using this library benifits you (and your library/frameworks's users) including..

1. Using it for providing values to the user

function database(name?: string): typeof InstanceDecorator {
    return Instance(function(values: Values, variableName: string) {
        values[variableName] = db.get(name ?? variableName)
    })
}

@Instance()
class Values {
    @database("value")
    value: string
}

2. Using it for making 'this' readonly

const FreezedBind = Instance(function(values: Values, name: string, descriptor: PropertyDescriptor) {
    const valuesClone = structuredClone(values)
    Object.freeze(valuesClone)
    values[name].bind(valuesClone)()
})

@Instance()
class Values {
    @FreezedBind
    method() {
        ...
    }
}

3. Using it for processing values that were set the first time

function Process<T>(processor: ((value: T) => T)): typeof InstanceDecorator {
    return Instance(function(values: Values, name: string) {
        let notProcessed = true
        let value = undefined
        Object.defineProperty(values, name, {
            get: function() { return value },
            set: function(newValue) {
                if (notProcessed) {
                    value = processor(newValue)
                    notProcessed = false
                } else value = newValue
            }
        })
    })
}

@Instance()
class Values {
    @Process<string>(function(value: string): string {
        console.log("processed " + value)
        return value
    })
    property: string
}

Guide

Step 1

To get started you will have to install the npm module:

$ npm install instance-decorators

and import it into your script:

const { Instance } = require("instance-decorators")

Step 2

You have to first decide what you want your decorator to decorate and depending on your decision you will put 2 or 3 arguments for your function.

2 parameters: (target, name), 3 parameters: (target, name, descriptor)

Then write your decorators by either giving it as an argument or using it as a decorator for the method in a class.

Choice 1: giving it as an argument

// this decorator will only work on methods
const decorator = Instance(function(target, name, descriptor) {
    ...
})
...

Choice 2: adding the decorator onto the decorator

class SomeDecorators {
    // this decorator will only work on properties
    // (note that we are not calling Instance)
    @Instance
    decorator(target, name) {
        ...
    }
    ...
}
...

Step 3

Decorate the class your decorator will be in with @Instance then simply use the decorator you created..

@Instance()
class SomeClass {
    @decorator
    // could also be a property depending on the decorator
    method() {
        ...
    }
}
...

Step 4

After that you can create a new instance for your class like this:

new SomeClass()

Example: Creating an @AutoRun decorator (finished product)

To try this example, you will have to install and import the library first..

What we want it to do

We want this decorator to automatically run methods after the class is constructed. This could declutter your code from:

class SomeClass {
    constructor() {
        this.method()
    }
    method() {
        console.log(`Ran method!`)
    }
}

to..

@Instance()
class SomeClass {
    @AutoRun()
    method() {
        console.log(`Ran method!`)
    }
}

Creating the decorator factory

In this decorator, we want it to accept a list of parameters to give to the function so we will have to create a factory.

// This factory accepts any parameter to pass on to the method
function AutoRun(...parameters: any[]) {
    return Instance(function(target: any, name: string, descriptor: PropertyDescriptor) {
        ...
    })
}

Adding code for the decorator

So after that, we will have to add some code to run the function with the passed parameters with method.apply(target, parameters)

// for the function passed to Instance()
function(target: any, name: string, descriptor: PropertyDescriptor) {
    // we binded target to the method to ensure that it runs with the class's 'this'
    target[name].apply(target, parameters)
}

Using the decorator

Then we can use it in any class that has the @Instance() decorator

@Instance()
class SomeClass {
    @AutoRun("some text")
    method(someText: string) {
        console.log(`Ran method!\nsomeText: '${someText}'`)
        // - console.log Output:
        // Ran method!
        // someText: 'some text'
    }
}
// Construct the class
new SomeClass()

Finished product

const { Instance } = require("instance-decorators")

// This factory accepts any parameter to pass on to the method
function AutoRun(...parameters: any[]) {
    return Instance(function(target: any, name: string, descriptor: PropertyDescriptor) {
        // we binded target to the method to ensure that it runs with the class's 'this'
        target[name].apply(target, parameters)
    })
}

// Using it
@Instance()
class SomeClass {
    @AutoRun("some text")
    method(someText: string) {
        console.log(`Ran method!\nsomeText: '${someText}'`)
        // - console.log Output:
        // Ran method!
        // someText: 'some text'
    }
}

// Construct the class
// (Try not constructing the class and see what happens..)
new SomeClass()

Documentation

@Instance(): ((target: any) => any)

This returns a decorator that modifies the class in order for instance decorators to work

Example

@Instance()
class SomeClass {
    ...
}
...

Instance(action: InstanceAction): InstanceDecorator

This creates an instance decorator with the given function.

Example

// it has to have 2 or 3 arguments depending on the type of decorator (properties or methods)
const decorator = Instance(function(target, name) { // and optionally a descriptor
    ...
})

@Instance

This is mostly the same as the previous one. The only differences are that it replaces the original method with a decorator with a type of typeof InstanceDecorator and the decorator will be used like @SomeClass.decorator instead of @decorator.

Example

class SomeClass {
    @Instance
    // it has to have 2 or 3 arguments depending on the type of decorator (properties or methods)
    static decorator(target, name) { // and optionally a descriptor
        ...
    }
}

Imports

The Instance function and the type InstanceDecorator are exported and can be acessed like this:

// You need to use 'typeof InstanceDecorator' instead of just 'InstanceDecorator'
const { Instance, InstanceDecorator } = require("instance-decorators")