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

@kzok/valueobject-ts

v2.0.1

Published

Tiny typesafe value object library for TypeScript

Downloads

6

Readme

@kzok/valueobject-ts


Tiny typesafe value object library for TypeScript.

CircleCI codecov

Features

  • ecmascript 5
  • less than 1k bytes with zero dependencies
  • commonjs & es module
  • typesafe and immutable class properties
  • object keys filtering in runtime

Brief example

import {valueObjectClass} from "@kzok/valueobject-ts";

type PersonProps = {
    name: string;
    age: number;
};

const personKeys = ["name", "age"] as const;

class Person extends valueObjectClass<PersonProps>().keys(personKeys) {
    greet(): string {
        return `Hello, I am ${this.name}.`;
    }
    growOne(): Person {
        return new Person({...this, age: this.age + 1});
    }
}

const initialValue = {
    name: "Bob",
    age: 20,
    greet: null,
    growOne: () => {
        throw new Error("The method won't be overwritten!");
    },
};
const person = new Person(initialValue);

console.log(person.greet());
// "Hello, I am Bob."
console.log(person.growOne().age);
// 21

Why and when to use this?

In TypeScript, you can easily create value object with parameter properties like the following:

class Person {
    constructor(public readonly name: string, public readonly age: number) {}
    greet(): string {
        return `Hello, I am ${this.name}.`;
    }
    growOne(): Person {
        return new Person(this.name, this.age + 1);
    }
}

However, with more properties, you'll want to use named parameters like the following:

class SomeLargeValueObject {
    public readonly prop1: number | null;
    public readonly prop2: number | null;
    public readonly prop3: number | null;
    /**
     * ... more props ...
     */
    constructor(args: {
        prop1: number | null;
        prop2: number | null;
        prop3: number | null;
        /**
         * ... more props ...
         */
    }) {
        this.prop1 = arg.prop1;
        this.prop2 = arg.prop2;
        this.prop3 = arg.prop3;
        /**
         * ... more assingments ...
         */
    }
}

With many properties, this approach is frustrating. So many prior value object libraries introduce following approach.

interface ValueObjectConstructor<T extends {[k: string]: any}> {
    new (initialValue: T): Readonly<T>;
}

const valueObject = <T extends {[k: string]: any}>(): ValueObjectConstructor<T> => {
    return class {
        constructor(arg: T) {
            Object.assign(this, arg);
        }
    } as any;
};

//-----------------

interface SomeLargeValueData {
    prop1: number | null;
    prop2: number | null;
    prop3: number | null;
    /**
     * ... more props ...
     */
}

class SomeLargeValueObject extends valueObject<SomeLargeValueData>() {
    isValid(): boolean {
        /** ... */
    }
}

In TypeScript, however, this approach has a problem. Because TypeScript doesn't have Exact Type, runtime error occurs in a following case.

const passedData = {
    prop1: 1,
    prop2: 2,
    prop3: 3,
    /**
     * ... more props ...
     */
    // Oops! This will overwrite the class method!
    isValid: true,
    /**
     * ... some more other props for other usecases ...
     */
};

const nextValueObject = new SomeLargeValueObject(passedData);

//-----------------

// TypeError: isValid is not a function
if (nextValueObject.isValid()) {
    /** ... */
}

Because of that, this library filters constructor argument's property keys.

Installation

Please use npm.

$ npm install valueobject.ts

Then, use javascript module bundler like webpack or rollup to bundle this library with your code.

API reference

#function valueObjectClass()

Returns object with a property keys which is the function that takes array of property keys to filter and return the base class of the value object.

Credits

  • This library is inspired by the prior arts below:
    • https://github.com/alexeyraspopov/dataclass
    • https://github.com/almin/ddd-base#valueobject