/**
 * Shape of the Macro function
 */
declare type MacroFn<T, Args extends any[], ReturnValue extends any> = (this: T, ...args: Args) => ReturnValue;
/**
 * Shape of the Getter function
 */
declare type GetterFn<T, ReturnValue extends any> = (this: T) => ReturnValue;
/**
 * Returns the typed variation of the macro by inspecting the
 * interface declaration
 */
declare type GetMacroFn<T, K> = K extends keyof T ? T[K] extends (...args: infer A) => infer B ? MacroFn<T, A, B> : MacroFn<T, any[], any> : MacroFn<T, any[], any>;
/**
 * Returns the typed variation of the getter by inspecting the
 * interface declaration
 */
declare type GetGetterFn<T, K> = K extends keyof T ? GetterFn<T, T[K]> : GetterFn<T, any>;
/**
 * Shape of the macroable constructor
 */
export interface MacroableConstructorContract<T extends any> {
    macro<K extends string>(name: K, callback: GetMacroFn<T, K>): void;
    getter<K extends string>(name: K, callback: GetGetterFn<T, K>, singleton?: boolean): void;
    hydrate(): void;
}
/**
 * Macroable is an abstract class to add ability to extend your class
 * prototype using better syntax.
 *
 * Macroable has handful of benefits over using traditional `prototype` approach.
 *
 * 1. Methods or properties added dynamically to the class can be removed using `hydrate` method.
 * 2. Can define singleton getters.
 */
export declare abstract class Macroable {
    protected static macros: {
        [key: string]: MacroFn<any, any[], any>;
    };
    protected static getters: {
        [key: string]: GetterFn<any, any>;
    };
    constructor();
    /**
     * Add a macro to the class. This method is a better to manually adding
     * to `class.prototype.method`.
     *
     * Also macros added using `Macroable.macro` can be cleared anytime
     *
     * @example
     * ```js
     * Macroable.macro('getUsername', function () {
     *   return 'virk'
     * })
     * ```
     */
    static macro<T extends any, K extends string>(this: {
        new (...args: any): T;
    }, name: string, callback: GetMacroFn<T, K>): void;
    /**
     * Return the existing macro or null if it doesn't exists
     */
    static getMacro(name: string): MacroFn<any, any[], any> | undefined;
    /**
     * Returns a boolean telling if a macro exists
     */
    static hasMacro(name: string): boolean;
    /**
     * Define a getter, which is invoked everytime the value is accessed. This method
     * also allows adding single getters, whose value is cached after first time
     *
     * @example
     * ```js
     * Macroable.getter('time', function () {
     *   return new Date().getTime()
     * })
     *
     * console.log(new Macroable().time)
     *
     * // Singletons
     * Macroable.getter('time', function () {
     *   return new Date().getTime()
     * }, true)
     *
     * console.log(new Macroable().time)
     * ```
     */
    static getter<T extends any, K extends string>(this: {
        new (...args: any): T;
    }, name: string, callback: GetGetterFn<T, K>, singleton?: boolean): void;
    /**
     * Return the existing getter or null if it doesn't exists
     */
    static getGetter(name: string): GetterFn<any, any> | undefined;
    /**
     * Returns a boolean telling if a getter exists
     */
    static hasGetter(name: string): boolean;
    /**
     * Cleanup getters and macros from the class
     */
    static hydrate(): void;
}
export {};
