declare type AnyDescriptor = TokenValueDescriptor<any> | TokenFactoryDescriptor<any> | TokenClassDescriptor<any>;

declare type ArgsOf<T, C = TokenType<T, T>> = C extends Newable ? OptionalArgs<ConstructorParameters<C>> : any[];

export declare class ArgumentsError extends Error {
    constructor(scope: string, className: string);
}

export declare class AsyncDependencyCycleError extends Error {
    constructor();
}

declare type BaseDescriptor = {
    beforeInject?: (container: Container, descriptor: AnyDescriptor, args: any[]) => any;
    beforeCreate?: (container: Container, descriptor: AnyDescriptor, args: any[]) => any;
};

export declare const childContainer: (name?: string) => Container;

export declare class Container {
    private parentContainer;
    name?: string | undefined;
    private instances;
    private resolutionContainer;
    private resolutionSet;
    private pendingPromiseMap;
    private tokenDescriptorMap;
    private resolutionsLoopCounter;
    constructor(parentContainer?: Container | null, name?: string | undefined);
    childContainer: (name?: string) => Container;
    $getInstance(descriptor: TokenClassDescriptor<any>, args?: any[], cache?: boolean): any;
    private getTokenDescriptor;
    private injectImpl;
    inject: <T extends TokenOrClass, Args extends ArgsOf<T>>(cls: T, ...args: Args) => InstanceOf<T>;
    injectAsync: <T extends TokenOrClass, Args extends ArgsOf<T>>(cls: T, ...args: Args) => Promise<InstanceOf<T>>;
    waitAsync: () => Promise<void>;
    register<T extends Token<any>>(descriptor: TokenValueDescriptor<T>): void;
    register<T extends Token<any>>(descriptor: TokenFactoryDescriptor<T>): void;
    register<T extends Token<any>>(descriptor: TokenClassDescriptor<T>): void;
    unregister: (token: TokenOrClass) => void;
    reset: () => void;
}

export declare class DependencyCycleError extends Error {
    constructor();
}

export declare const globalContainer: Container;

export declare const inject: <T extends TokenOrClass, Args extends ArgsOf<T, T extends Token<infer U> ? U : T>>(cls: T, ...args: Args) => InstanceOf<T, T extends Token<infer U> ? U : T>;

export declare type Injectable<C extends I, I extends ScopedClass = ScopedClass> = InstanceType<I>;

export declare const injectAsync: <T extends TokenOrClass, Args extends ArgsOf<T, T extends Token<infer U> ? U : T>>(cls: T, ...args: Args) => Promise<InstanceOf<T, T extends Token<infer U> ? U : T>>;

declare type InstanceOf<T, C = TokenType<T, T>> = C extends Newable ? InstanceType<C> : C;

declare type Newable<T = any> = new (...args: any[]) => T;

declare type OptionalArgs<T, R = Required<T>> = R extends readonly [...infer Rest, infer Last] ? R | OptionalArgs<Rest> : [];

export declare interface ScopedClass {
    new (...args: any[]): any;
    scope: ScopeHandler;
}

declare type ScopeHandler = (cls: any, args: any[], container: Container, resolutionContainer: Container) => any;

export declare class Scopes {
    static Singleton(): ScopeHandler;
    static Transient(): ScopeHandler;
    static Container(): ScopeHandler;
    static Resolution(): ScopeHandler;
    static Scoped: typeof Scopes.Container;
}

export declare class Token<T> {
    readonly name?: string | undefined;
    constructor(name?: string | undefined);
}

export declare type TokenClassDescriptor<T extends Token<any>> = BaseDescriptor & {
    token?: T;
    class: Newable<TokenType<T>>;
    scope?: ScopeHandler;
};

export declare type TokenFactoryDescriptor<T extends Token<any>> = BaseDescriptor & {
    token: T;
    factory: (container: Container, ...args: any[]) => TokenType<T>;
};

export declare class TokenNotRegisteredError extends Error {
    constructor();
}

declare type TokenOrClass = Token<any> | ScopedClass;

declare type TokenType<T, R = any> = T extends Token<infer U> ? U : R;

export declare type TokenValueDescriptor<T extends Token<any>> = BaseDescriptor & {
    token: T;
    value: TokenType<T>;
};

export { }
