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

class-constructor

v0.2.3

Published

Tool to implement builder pattern that actually uses class constructor with ease

Readme

Introduction

This library is designed to help you build classes with optional properties using the builder pattern. It discovers class fields and creates optimized builder that works faster than implicit builder implementation.

According to benchmarks, the generated builder is up to 25% faster than traditional builder implementations.

Navigation

Installation

npm install class-constructor

or

yarn add class-constructor

or

pnpm add class-constructor

Important!

Make following changes in your tsconfig.json:

{
  "compilerOptions": {
    // set useDefineForClassFields to true for correct class fields initialization
    // this option will set undefined to uninitialized fields that will allow builder to track them
    "useDefineForClassFields": true,
    // or target is ES2022 or higher
    "target": "ES2022",
    // note: that is highly recommended to set target to ES2022 or higher

  }
}

That will enable usage of upcoming standard version of class fields, that is necessary for builder to index fields.

Compatibility

Latest version of the package gets rid of ES6 Proxy. It not only significantly improved performance, but also made the library compatible with older environments (just make sure you have useDefineForClassFields set to true in your tsconfig.json). For target lower than ES2022, there may be issues with performance, but that was not proved yet.

Builder pattern

Builder pattern is a design pattern that allows you to build complex objects step by step. Example:

// for example, we have a Button class
// it has a required property 'text' and optional properties 'color' and 'size' and 10 more ...
// if all those properties would be accepted through constructor, it would be a mess
// we should have remember an order of arguments, and it would be hard to read and maintain
new Button('Click me', undefined, undefined, 'red');

// instead, we can use builder pattern
// it allows us to build an object step by step
Button.builder('Click me').withColor('red').build();

But, the builder pattern is not easy to implement, and it requires a lot of boilerplate code.

Examples

class-constructor library allows you to create builders with just few lines of code.

Basic usage

import { toBuilderMethod } from 'class-constructor';

class Button {
  public text: string;

  public color?: string;

  public size?: string;

  constructor(text: string) {
    this.text = text;
  }

  public static builder = toBuilderMethod(Button).classAsOptionals();
}

// and here we go
const buttonBuilder = Button.builder('Click me');
buttonBuilder.color('red');
console.log(buttonBuilder.color()); // 'red'
buttonBuilder.build();
// ^ class Button { text: 'Click me', color: 'red', size: undefined }

Default values

You can set default values for optional properties:

class Button {
  public text: string;

  public color?: string = 'red';

  public size?: string = 'small';

  constructor(text: string) {
    this.text = text;
  }

  public static builder = toBuilderMethod(Button).classAsOptionals();
}

Button.builder('Click me').color('blue').build();
// ^ class Button { text: 'Click me', color: 'blue', size: 'small' }

Private properties

If you have private properties in your class, you still can build class with them. But to do so, you will need to create an interface to let TypeScript know about them.

interface ButtonOptionals {
  color?: string; // note that we don't have _ prefix here
  size?: string;
}

class Button {
  private _text: string;
  // we prefix private properties with "_" even if builder option interface doesn't have them
  // class builder will find them and be able to set them
  private _color?: string = 'red';
  private _size?: string = 'small';

  constructor(text: string) {
    this._text = text;
  }

  public static builder = toBuilderMethod(Button).withOptionals<ButtonOptionals>();

  // ... getters and setters ...
}

Button.builder('Click me').color('blue').build();
// ^ class Button { _text: 'Click me', _color: 'blue', _size: 'small' }

Property accessors

Accessor priority

interface WithPrivateAndPublicPropertyOptionals {
  name: string;
}

class WithPrivateAndPublicProperty {
  private _name?: string;

  // property with full match will be preferred over private property
  public name?: string;

  static builder = toBuilderMethod(WithPrivateAndPublicProperty).withOptionals<WithPrivateAndPublicPropertyOptionals>();
}

WithPrivateAndPublicProperty.builder().name('Jake').build();
// ^ class WithPrivateAndPublicProperty { _name: undefined, name: 'Jake' }

Getters and setters

Getters and setters will be ignored by default.

class WithGetterAndSetter {
  private _name?: string;

  public get name() {
    console.log('getter');
    return this._name;
  }

  public set name(value: string) {
    console.log('setter', value);
    this._name = value;
  }

  public static builder = toBuilderMethod(WithGetterAndSetter).classAsOptionals();
}

const builder = WithGetterAndSetter.builder();
builder.name('Jake');
// no console.log called

console.log(builder.name()); // 'Jake'
// no console.log called

builder.build();
// ^ class WithGetterAndSetter { _name: 'Jake' }

To enable getters and setters, you can use BuilderAccessors decorator.

class WithGetterAndSetter {
  @BuilderAccessors((target) => target.name, (target, value) => (target._name = value))
  private _name?: string;

  public get name() {
    return this._name;
  }

  public set name(value: string) {
    console.log('setter', value);
    this._name = value;
  }

  public static builder = toBuilderMethod(WithGetterAndSetter).classAsOptionals();
}

const builder = WithGetterAndSetter.builder();
builder.name('Jake');
// console.log called: > setter

console.log(builder.name()); // 'Jake'
// console.log called: > getter

builder.build();
// ^ class WithGetterAndSetter { _name: 'Jake' }