type GenericFn = (...args: any[]) => any;
type GenericParams = Parameters<GenericFn>;
type OnceWrapperFn = GenericFn & {
    once: boolean;
};
/**
 * When the service receives a "once subscription", it needs to track the listener so it
 * gets removed after being called once, and to avoid modifying the original function, it
 * creates a wrapper function that has the "once" property set to true. The wrapper and
 * the original function are stored in case `off` is called before the wrapper gets
 * triggered; it will receive the original function, not the wrapper, so the class needs a
 * way to map them together.
 */
type OnceWrapper = {
    /**
     * A simple wrapper for the original listener, with the difference that it has a `once`
     * property set to `true`.
     */
    wrapper: OnceWrapperFn;
    /**
     * The original listener that will be called once.
     */
    original: GenericFn;
};
/**
 * A minimal implementation of an events handler service.
 */
declare class EventsHub {
    /**
     * A dictionary of the events and their listeners.
     */
    protected events: Record<string, GenericFn[]>;
    /**
     * A dictionary of wrappers that were created for "one time subscriptions". This is
     * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it
     * will look for a wrapper and remove it.
     */
    protected onceWrappers: Record<string, OnceWrapper[]>;
    /**
     * Gets all the listeners for a specific event.
     * The list is returned by reference, so it can be modified once obtained.
     *
     * @param event  The name of the event.
     */
    protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[];
    on<ListenerFn extends GenericFn = GenericFn>(event: string, listener: ListenerFn): () => boolean;
    on<ListenerFn extends GenericFn = GenericFn>(event: string[], listener: ListenerFn): () => boolean[];
    on<ListenerFn extends GenericFn = GenericFn>(event: string | string[], listener: ListenerFn): () => boolean | boolean[];
    once<ListenerFn extends GenericFn = GenericFn>(event: string, listener: ListenerFn): () => boolean;
    once<ListenerFn extends GenericFn = GenericFn>(event: string[], listener: ListenerFn): () => boolean[];
    once<ListenerFn extends GenericFn = GenericFn>(event: string | string[], listener: ListenerFn): () => boolean | boolean[];
    off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(event: string[], listener: ListenerFn): boolean[];
    off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(event: string, listener: ListenerFn): boolean;
    off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(event: string | string[], listener: ListenerFn): boolean | boolean[];
    /**
     * Emits an event and call all its listeners.
     *
     * @param event  An event name or a list of them.
     * @param args   A list of parameters to send to the listeners.
     * @template Args  The type of the parameters to send to the listeners.
     * @example
     *
     *   const events = new EventsHub();
     *   events.on('event', (arg0) => {
     *     console.log(`Event received: ${arg0}`);
     *   });
     *   events.emit('event', 'Hello'); // prints "Event received: Hello"
     *
     */
    emit<Args extends GenericParams>(event: string | string[], ...args: Args): void;
    /**
     * Asynchronously reduces a target using an event. It's like emit, but the events
     * listener return a modified (or not) version of the `target`.
     *
     * @param event   An event name or a list of them.
     * @param target  The variable to reduce with the reducers/listeners.
     * @param args    A list of parameters to send to the reducers/listeners.
     * @returns A version of the `target` processed by the listeners.
     * @template Target  The type of the target.
     * @template Args    The type of the parameters to send to the reducers/listeners.
     * @example
     *
     *   const events = new EventsHub();
     *   events.on('event', async (target, arg0) => {
     *     const data = await fetch(`https://api.example.com/${arg0}`);
     *     target.push(data);
     *     return target;
     *   });
     *   const result = await events.reduce('event', [], 'Hello');
     *   // result would be a list of data fetched from the API.
     *
     */
    reduce<Target, Args extends GenericParams>(event: string | string[], target: Target, ...args: Args): Promise<Target>;
    /**
     * Synchronously reduces a target using an event. It's like emit, but the events
     * listener return a modified (or not) version of the `target`.
     *
     * @param event   An event name or a list of them.
     * @param target  The variable to reduce with the reducers/listeners.
     * @param args    A list of parameters to send to the reducers/listeners.
     * @returns A version of the `target` processed by the listeners.
     * @template Target  The type of the target.
     * @template Args    The type of the parameters to send to the reducers/listeners.
     * @example
     *
     *   const events = new EventsHub();
     *   events.on('event', (target, arg0) => {
     *     target.push(arg0);
     *     return target;
     *   });
     *   events.reduce('event', [], 'Hello'); // returns ['Hello']
     *
     */
    reduceSync<Target, ReducerArgs extends GenericParams>(event: string | string[], target: Target, ...args: ReducerArgs): Target;
}
/**
 * Shorthand for `new EventsHub()`.
 *
 * @returns A new instance of {@link EventsHub}.
 */
declare const eventsHub: () => EventsHub;

export { EventsHub, eventsHub };
