class-constructor
Version:
Tool to implement builder pattern that actually uses class constructor with ease
131 lines (122 loc) • 4.74 kB
text/typescript
interface OptionalBuilderPropertyMetadata {
desiredPropertyKey: string;
}
/**
* Represents an abstract class constructor type.
* @template T The instance type of the class, defaults to any
* @returns A constructor type that creates instances of T
*/
type Clazz<T = any> = abstract new (...args: any[]) => T;
/**
* Represents a concrete (instantiable) class constructor type.
* @template T The instance type of the class, defaults to any
* @returns A constructor type that creates instances of T
*/
type InstantiableClazz<T = any> = new (...args: any[]) => T;
type StringPropertyKeyParameterDecorator = (target: Object, propertyKey: string) => void;
/**
* Interface for a fluent builder pattern.
* Provides getter/setter methods for each optional property and a build() method.
*
* @typeParam TOptionals - Type containing optional properties that can be set
* @typeParam TClass - The class type being built
*
* @example
* ```typescript
* interface Options {
* optionalProperty?: string;
* }
*
* const builder: Builder<Options, MyClass> = MyClass.builder('required');
* const instance = builder
* .optionalProperty('value') // Set value
* .optionalProperty() // Get current value
* .build(); // Create instance
* ```
*/
type Builder<TOptionals, TClass> = {
[K in keyof TOptionals]-?: ((arg: TOptionals[K]) => Builder<TOptionals, TClass>) & (() => TOptionals[K]);
} & {
build(): TClass;
};
/**
* Utility type that extracts the instance type from a class constructor.
* @template T The class constructor type
* @returns The instance type of the class
*/
type ClassInstance<T> = T extends InstantiableClazz<infer U> ? U : never;
interface BuilderObject<TClass extends InstantiableClazz = any> {
instance: any;
[key: string]: ((value: unknown) => BuilderObject<TClass>) | (() => unknown);
build: () => ClassInstance<TClass>;
}
/**
* Creates a builder for a class with required constructor parameters and optional properties.
*
* @param classConstructor - The class to build
* @param parameters - Required constructor parameters
* @returns A builder instance that provides fluent methods for setting optional properties
*
*/
declare function ParametrizedBuilder<TClass extends InstantiableClazz, TOptionals = ClassInstance<TClass>>(classConstructor: TClass, parameters: ConstructorParameters<TClass>): Builder<TOptionals, ClassInstance<TClass>>;
/**
* Decorator that specifies custom getter and setter functions for a builder property.
* This allows customizing how properties are accessed and modified during the build process.
*
* @param get - Function to get the property value from the target object
* @param set - Function to set the property value on the target object
* @returns PropertyDecorator function
*
* @example
* ```typescript
* class MyClass {
* @BuilderAccessors(
* (target) => target._property,
* (target, value) => target.property = value
* )
* private _property?: string;
*
* set property(value: string) {
* this._property = value.toUpperCase();
* }
* }
* ```
*/
declare function BuilderAccessors<T extends object, V>(get: (target: T) => V, set: (target: T, value: V) => void): (target: T, propertyKey: string) => void;
interface BuilderMethodFactory<TClass extends InstantiableClazz> {
withOptionals<TOptionals>(): (...args: ConstructorParameters<TClass>) => Builder<TOptionals, ClassInstance<TClass>>;
classAsOptionals(): (...args: ConstructorParameters<TClass>) => Builder<ClassInstance<TClass>, ClassInstance<TClass>>;
}
/**
* Creates a builder method factory for a class that can generate builders with different optional property configurations.
*
* @param clazz - The class to create a builder for
* @returns A factory object with methods to create different types of builders
*
* @example
* ```typescript
*
* interface MyOptionals {
* optional?: string;
* }
*
* class MyClass {
* constructor(public required: string) {}
* private _optional?: string;
*
* static builder = toBuilderMethod(MyClass).withOptionals<MyOptionals>();
* }
* ```
* @example
* ```typescript
*
* class MyClass {
* constructor(public required: string) {}
* public optional?: string;
*
* static builder = toBuilderMethod(MyClass).classAsOptionals();
* }
* ```
*/
declare function toBuilderMethod<TClass extends InstantiableClazz>(clazz: TClass): BuilderMethodFactory<TClass>;
export { type Builder, BuilderAccessors, type BuilderMethodFactory, type BuilderObject, type ClassInstance, type Clazz, type InstantiableClazz, type OptionalBuilderPropertyMetadata, ParametrizedBuilder, type StringPropertyKeyParameterDecorator, toBuilderMethod };