type Class<T = unknown> = new (...args: unknown[]) => T;

type Token = string | symbol | Class;

declare const inject: (token: Token) => any;

declare const injectable: <C extends Class>(tokenOverride?: Token) => (target: C, _context: ClassDecoratorContext<C>) => void;

interface ClassProvider {
    class: Class;
}
interface FunctionProvider {
    factory: (...args: unknown[]) => unknown;
}
interface ValueProvider {
    value: unknown;
}
type Provider = ClassProvider | FunctionProvider | ValueProvider;

declare class Giver {
    providerRegistry: Map<Token, Provider>;
    registerTokenForClass: (token: Token, classToProvide: Class) => void;
    instanceOf: <T extends Token>(token: T) => T extends Class ? InstanceType<T> : T;
}

declare const giverInstance: Giver;

export { giverInstance, inject, injectable };
