Naysayers Promote Misery

    @kzok/valueobject-ts
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.1 • Public • Published

    @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

    Install

    npm i @kzok/valueobject-ts

    DownloadsWeekly Downloads

    2

    Version

    2.0.1

    License

    MIT

    Unpacked Size

    490 kB

    Total Files

    7

    Last publish

    Collaborators

    • kzok