declare type IBuilder<T> = {
    [k in keyof T]-?: ((arg: T[k]) => IBuilder<T>) & (() => T[k]);
} & {
    build(): T;
};
declare type Clazz<T> = new (...args: unknown[]) => T;
/**
 * Create a Builder for a class. Returned objects will be of the class type.
 *
 * e.g. let obj: MyClass = Builder(MyClass).setA(5).setB("str").build();
 *
 * @param type the name of the class to instantiate.
 * @param template optional class partial which the builder will derive initial params from.
 * @param override optional class partial which the builder will override params from when calling build().
 */
declare function Builder<T>(type: Clazz<T>, template?: Partial<T> | null, override?: Partial<T> | null): IBuilder<T>;
/**
 * Create a Builder for an interface. Returned objects will be untyped.
 *
 * e.g. let obj: Interface = Builder<Interface>().setA(5).setB("str").build();
 *
 * @param template optional partial object which the builder will derive initial params from.
 * @param override optional partial object which the builder will override params from when calling build().
 */
declare function Builder<T>(template?: Partial<T> | null, override?: Partial<T> | null): IBuilder<T>;

declare type IStrictBuilder<T, B = Record<string, unknown>> = {
    [k in keyof T]-?: ((arg: T[k]) => IStrictBuilder<T, B & Record<k, T[k]>>) & (() => T[k]);
} & {
    build: B extends T ? () => T : never;
};
/**
 * Create a StrictBuilder for an interface. Returned objects will be untyped.
 *
 * e.g. let obj: Interface = StrictBuilder<Interface>().setA(5).setB("str").build();
 *
 */
declare function StrictBuilder<T>(): IStrictBuilder<T>;

export { Builder, IBuilder, IStrictBuilder, StrictBuilder };
