type DependencyKey = symbol | string;
type ModuleKey = symbol | string;
interface DependencyObject {
    [key: string]: DependencyKey;
}
type DependencyArray = DependencyKey[];
type Scope = 'singleton' | 'transient' | 'scoped';
interface DefaultRegistry {
    [key: string]: unknown;
}
type RegistryKey<TRegistry> = Extract<keyof TRegistry, DependencyKey>;
type MatchingRegistryKeys<TRegistry, T> = {
    [K in RegistryKey<TRegistry>]: TRegistry[K & keyof TRegistry] extends T ? K : never;
}[RegistryKey<TRegistry>];
type ValidatedArrayDependencies<TRegistry, TParameters extends readonly unknown[]> = {
    readonly [I in keyof TParameters]: MatchingRegistryKeys<TRegistry, TParameters[I]>;
};
type NonTupleArray<T extends readonly unknown[]> = number extends T['length'] ? T : never;
type CompatibleArrayDependencies<TRegistry, TParameters extends readonly unknown[]> = readonly MatchingRegistryKeys<TRegistry, TParameters[number]>[];
type ValidatedObjectDependencies<TRegistry, TParameter> = {
    [P in keyof TParameter]: MatchingRegistryKeys<TRegistry, TParameter[P]>;
};
type ValidDependenciesForParameters<TRegistry, TParameters extends readonly unknown[]> = TParameters extends readonly [] ? never : TParameters extends readonly [infer Only, ...infer Rest] ? Rest extends [] ? Only extends Record<string, unknown> ? ValidatedArrayDependencies<TRegistry, [Only]> | ValidatedObjectDependencies<TRegistry, Only> : ValidatedArrayDependencies<TRegistry, [Only]> : ValidatedArrayDependencies<TRegistry, TParameters> : never;
type ValidDependenciesFor<TRegistry, TClass extends new (...args: any[]) => any> = ValidDependenciesForParameters<TRegistry, ConstructorParameters<TClass>>;
type ValidFunctionDependenciesFor<TRegistry, TFunction extends (...args: any[]) => any> = ValidDependenciesForParameters<TRegistry, Parameters<TFunction>>;
type IncompatibleOverride<K extends PropertyKey, Expected, Provided> = {
    __error: 'Incompatible override type for registry key';
    key: K;
    expected: Expected;
    provided: Provided;
};
type CompatibleKey<TRegistry, TOverride> = [TOverride] extends [never] ? RegistryKey<TRegistry> : {
    [K in RegistryKey<TRegistry>]: TOverride extends TRegistry[K] ? K : IncompatibleOverride<K, TRegistry[K], TOverride>;
}[RegistryKey<TRegistry>];
type TypedResolveFunction<TRegistry> = <TOverride = never, K extends CompatibleKey<TRegistry, TOverride> = CompatibleKey<TRegistry, TOverride>>(key: K) => [TOverride] extends [never] ? TRegistry[K & keyof TRegistry] : TOverride;
interface Bindable {
    bind(key: DependencyKey): {
        toValue: (value: unknown) => void;
        toFunction: (fn: CallableFunction) => void;
        toHigherOrderFunction: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
        toCurry: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
        toFactory: (factory: CallableFunction, scope?: Scope) => void;
        toClass: <C>(constructor: new (...args: any[]) => C, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
    };
}
interface TypedBindable<TRegistry> {
    bind<K extends RegistryKey<TRegistry>>(key: K): {
        toValue: (value: TRegistry[K]) => void;
        toFunction: (fn: TRegistry[K] extends CallableFunction ? TRegistry[K] : never) => void;
        toHigherOrderFunction: {
            <TFunction extends (...args: readonly []) => TRegistry[K]>(fn: TFunction, dependencies?: undefined, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K]>(fn: TFunction, dependencies: ValidFunctionDependenciesFor<TRegistry, TFunction>, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K], const TDependencies extends CompatibleArrayDependencies<TRegistry, Parameters<TFunction>>>(fn: TFunction, dependencies: NonTupleArray<TDependencies>, scope?: Scope): void;
        };
        toCurry: {
            <TFunction extends (...args: readonly []) => TRegistry[K]>(fn: TFunction, dependencies?: undefined, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K]>(fn: TFunction, dependencies: ValidFunctionDependenciesFor<TRegistry, TFunction>, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K], const TDependencies extends CompatibleArrayDependencies<TRegistry, Parameters<TFunction>>>(fn: TFunction, dependencies: NonTupleArray<TDependencies>, scope?: Scope): void;
        };
        toFactory: (factory: (resolve: TypedResolveFunction<TRegistry>) => TRegistry[K], scope?: Scope) => void;
        toClass: {
            <TClass extends new () => TRegistry[K]>(constructor: TClass, dependencies?: undefined, scope?: Scope): void;
            <TClass extends new (...args: any[]) => TRegistry[K]>(constructor: TClass, dependencies: ValidDependenciesFor<TRegistry, TClass>, scope?: Scope): void;
            <TClass extends new (...args: any[]) => TRegistry[K], const TDependencies extends CompatibleArrayDependencies<TRegistry, ConstructorParameters<TClass>>>(constructor: TClass, dependencies: NonTupleArray<TDependencies>, scope?: Scope): void;
        };
    };
    bind(key: DependencyKey): {
        toValue: (value: unknown) => void;
        toFunction: (fn: CallableFunction) => void;
        toHigherOrderFunction: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
        toCurry: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
        toFactory: (factory: CallableFunction, scope?: Scope) => void;
        toClass: <C>(constructor: new (...args: any[]) => C, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
    };
}
interface Container extends Bindable {
    load(moduleKey: ModuleKey, module: Module): void;
    get<T>(key: DependencyKey): T;
    unload(key: ModuleKey): void;
    runInScope<T>(callback: () => T): T;
}
interface TypedContainer<TRegistry> {
    bind<K extends RegistryKey<TRegistry>>(key: K): {
        toValue: (value: TRegistry[K]) => void;
        toFunction: (fn: TRegistry[K] extends CallableFunction ? TRegistry[K] : never) => void;
        toHigherOrderFunction: {
            <TFunction extends (...args: readonly []) => TRegistry[K]>(fn: TFunction, dependencies?: undefined, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K]>(fn: TFunction, dependencies: ValidFunctionDependenciesFor<TRegistry, TFunction>, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K], const TDependencies extends CompatibleArrayDependencies<TRegistry, Parameters<TFunction>>>(fn: TFunction, dependencies: NonTupleArray<TDependencies>, scope?: Scope): void;
        };
        toCurry: {
            <TFunction extends (...args: readonly []) => TRegistry[K]>(fn: TFunction, dependencies?: undefined, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K]>(fn: TFunction, dependencies: ValidFunctionDependenciesFor<TRegistry, TFunction>, scope?: Scope): void;
            <TFunction extends (...args: any[]) => TRegistry[K], const TDependencies extends CompatibleArrayDependencies<TRegistry, Parameters<TFunction>>>(fn: TFunction, dependencies: NonTupleArray<TDependencies>, scope?: Scope): void;
        };
        toFactory: (factory: (resolve: TypedResolveFunction<TRegistry>) => TRegistry[K], scope?: Scope) => void;
        toClass: {
            <TClass extends new () => TRegistry[K]>(constructor: TClass, dependencies?: undefined, scope?: Scope): void;
            <TClass extends new (...args: any[]) => TRegistry[K]>(constructor: TClass, dependencies: ValidDependenciesFor<TRegistry, TClass>, scope?: Scope): void;
            <TClass extends new (...args: any[]) => TRegistry[K], const TDependencies extends CompatibleArrayDependencies<TRegistry, ConstructorParameters<TClass>>>(constructor: TClass, dependencies: NonTupleArray<TDependencies>, scope?: Scope): void;
        };
    };
    load<TModuleRegistry>(moduleKey: ModuleKey, module: TypedModule<TModuleRegistry>): void;
    load(moduleKey: ModuleKey, module: Module): void;
    get<TOverride = never, K extends CompatibleKey<TRegistry, TOverride> = CompatibleKey<TRegistry, TOverride>>(key: K): [TOverride] extends [never] ? TRegistry[K & keyof TRegistry] : TOverride;
    unload(key: ModuleKey): void;
    runInScope<T>(callback: () => T): T;
}
interface Module extends Bindable {
    bindings: Map<DependencyKey, Binding>;
}
interface TypedModule<TRegistry> extends TypedBindable<TRegistry> {
    bindings: Map<DependencyKey, Binding>;
}
interface InjectionTokens {
    [key: string]: DependencyKey;
}
type ResolveFunction = (dep: DependencyKey) => unknown;
interface Binding {
    factory: (resolve: (key: DependencyKey) => unknown) => unknown;
    scope: Scope;
}

declare function createContainer(): Container;
declare function createContainer<TRegistry>(): TypedContainer<TRegistry>;

declare function createModule(): Module;
declare function createModule<TRegistry>(): TypedModule<TRegistry>;

export { type Binding, type Container, type DefaultRegistry, type DependencyArray, type DependencyKey, type DependencyObject, type InjectionTokens, type Module, type ModuleKey, type ResolveFunction, type Scope, type TypedContainer, type TypedModule, type TypedResolveFunction, createContainer, createModule };
