import 'reflect-metadata';
import * as Joi from 'joi';
export declare const getJoi: (options?: {
    joi?: typeof Joi;
} | undefined) => Joi.Root;
export declare const WORKING_SCHEMA_KEY = "tsdv:working-schema";
export declare const SCHEMA_KEY = "tsdv:schema";
export declare const JOI_VERSION: Version;
export declare type WorkingSchema = {
    [index: string]: Joi.Schema;
};
export interface Constructor<T> {
    new (...args: any[]): T;
}
export declare type AnyClass = Constructor<any>;
export declare type StringKey<T> = Extract<keyof T, string>;
export declare type StringOrSymbolKey<T> = Extract<keyof T, string | symbol>;
/**
 * If a given type extends the desired type, return the given type. Otherwise, return the desired type.
 * So, you can do stuff like this:
 *
 * ```typescript
 * interface Foo {
 *     bar: null;
 *     baz: number;
 *     boz: string;
 *     biz: string | null;
 * }
 *
 * const bars1: AllowUnions<Foo['baz'], number, Foo['baz']>[] = [
 *     'sdf', // Type 'string' is not assignable to type 'number'.
 *     null, // Type 'null' is not assignable to type 'number'.
 *     123
 * ];
 *
 * const bars2: AllowUnions<Foo['boz'], string, Foo['boz']>[] = [
 *     'sdf',
 *     null, // Type 'null' is not assignable to type 'string'.
 *     123 // Type 'number' is not assignable to type 'string'.
 * ];
 *
 * const bars3: AllowUnions<Foo['biz'], string, Foo['biz']>[] = [
 *     'sdf',
 *     null,
 *     123 // Type 'number' is not assignable to type 'string | null'.
 * ];
 * ```
 *
 * Notice that you pass the TOriginal type parameter, which is identical to the TType type parameter. This is because
 * the "extends" condition will narrow the type of TType to just TDesired. So, "string | null" will be narrowed to
 * "string", but we actually want to return the original "string | null".
 *
 * By returning the TDesired when there's no match, we get nice error messages that state what the desired type was.
 */
export declare type AllowUnions<TType, TDesired, TOriginal> = TType extends TDesired ? TOriginal : TDesired;
export declare type MapAllowUnions<TObject, TKey extends keyof TObject, TDesired> = {
    [K in TKey]: AllowUnions<TObject[K], TDesired, TObject[K]>;
};
export declare type TypedPropertyDecorator<TPropertyType> = (<TClass extends MapAllowUnions<TClass, TKey, TPropertyType>, TKey extends StringOrSymbolKey<TClass>>(target: TClass, propertyKey: TKey) => void);
export declare function getWorkingSchema<TClass>(target: TClass): WorkingSchema | undefined;
export declare function getMergedWorkingSchemas(target: object): WorkingSchema | undefined;
export declare function getJoiSchema(Class: AnyClass, joi: Pick<typeof Joi, 'object'>): Joi.ObjectSchema | undefined;
export declare function updateWorkingSchema<TClass, TKey extends StringOrSymbolKey<TClass>>(target: TClass, propertyKey: TKey, schema: Joi.Schema): void;
export interface Version {
    major: string;
    minor: string;
    patch: string;
}
export declare function parseVersionString(version: string): {
    major: string;
    minor: string;
    patch: string;
};
export declare function getJoiVersion(joi: typeof Joi | undefined): Version;
export declare class IncompatibleJoiVersion extends Error {
    constructor(actualVersion: Version);
}
export declare function checkJoiIsCompatible(joi: typeof Joi | undefined): void;
