declare const CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = "___CTOR_ARGS___";
declare const CONSTRUCTOR_ARGUMENTS_SYMBOL: unique symbol;

interface ContainerIdentifierable {
    identifier: string;
}
type NewableService<T> = new (...args: any[]) => T;
type CustomConstructableService<T> = (...args: any[]) => T;
type ConstructorArgument = string | undefined;
interface WithConstructorArgumentsSymbol {
    [CONSTRUCTOR_ARGUMENTS_SYMBOL]?: ConstructorArgument[];
}
type Implementation<T> = NewableService<T> & WithConstructorArgumentsSymbol;
type ImplementationInstance<T> = CustomConstructableService<T> & WithConstructorArgumentsSymbol;
interface RegisterOptionsBase extends ContainerIdentifierable {
}
interface RegisterOptionsWithImplementation<T> extends RegisterOptionsBase {
    implementation: Implementation<T> | null;
}
interface RegisterOptionsWithoutImplementation extends RegisterOptionsBase {
}
type RegisterOptions<T> = RegisterOptionsWithImplementation<T> | RegisterOptionsWithoutImplementation;
interface HasOptions extends ContainerIdentifierable {
}
interface GetOptions extends ContainerIdentifierable {
}
interface IDIContainer {
    registerSingleton<T, U extends T = T>(newExpression?: ImplementationInstance<U>, options?: RegisterOptions<U>): void;
    registerSingleton<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: RegisterOptionsWithoutImplementation): void;
    registerSingleton<T, U extends T = T>(newExpression: undefined, options: RegisterOptionsWithImplementation<U>): void;
    registerTransient<T, U extends T = T>(newExpression?: ImplementationInstance<U>, options?: RegisterOptions<U>): void;
    registerTransient<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: RegisterOptionsWithoutImplementation): void;
    registerTransient<T, U extends T = T>(newExpression: undefined, options: RegisterOptionsWithImplementation<U>): void;
    get<T>(options?: GetOptions): T;
    has<T>(options?: HasOptions): boolean;
}

/**
 * A Dependency-Injection container that holds services and can produce instances of them as required.
 * It mimics reflection by parsing the app at compile-time and supporting the generic-reflection syntax.
 * @author Frederik Wessberg
 */
declare class DIContainer implements IDIContainer {
    #private;
    get [Symbol.toStringTag](): string;
    /**
     * Registers a service that will be instantiated once in the application lifecycle. All requests
     * for the service will retrieve the same instance of it.
     *
     * You should not pass any options to the method if using the compiler. It will do that automatically.
     */
    registerSingleton<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: RegisterOptionsWithoutImplementation): void;
    registerSingleton<T, U extends T = T>(newExpression: undefined, options: RegisterOptionsWithImplementation<U>): void;
    registerSingleton<T, U extends T = T>(newExpression?: ImplementationInstance<U>, options?: RegisterOptions<U>): void;
    /**
     * Registers a service that will be instantiated every time it is requested throughout the application lifecycle.
     * This means that every call to get() will return a unique instance of the service.
     *
     * You should not pass any options to the method if using the compiler. It will do that automatically.
     */
    registerTransient<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: RegisterOptionsWithoutImplementation): void;
    registerTransient<T, U extends T = T>(newExpression: undefined, options: RegisterOptionsWithImplementation<U>): void;
    registerTransient<T, U extends T = T>(newExpression?: ImplementationInstance<U>, options?: RegisterOptions<U>): void;
    /**
     * Gets an instance of the service matching the interface given as a generic type parameter.
     * For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
     * generic interface name.
     *
     * You should not pass any options to the method if using the compiler. It will do that automatically.
     */
    get<T>(options?: GetOptions): T;
    /**
     * Returns true if a service has been registered matching the interface given as a generic type parameter.
     * For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
     * generic interface name.
     *
     * You should not pass any options to the method if using the compiler. It will do that automatically.
     */
    has<T>(options?: HasOptions): boolean;
}

export { CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER, DIContainer, type IDIContainer };
