import "joi";
export { tuple } from './tuple';
declare module "joi" {
    type primitiveType = string | number | boolean | Function | Date | undefined | null | void;
    type schemaMap = {
        [key: string]: mappedSchema;
    };
    type mappedSchema = SchemaLike | mappedSchemaMap;
    type mappedSchemaMap<T extends schemaMap = any> = {
        [K in keyof T]: T[K];
    };
    interface StringSchema<N = string> extends AnySchema {
        valid<T extends string>(...values: T[]): StringSchema<typeof values[number]>;
        valid<T extends string[]>(values: T): StringSchema<typeof values[number]>;
        valid(...values: any[]): this;
        valid(values: any[]): this;
    }
    function string<T extends string>(): StringSchema<extractType<T>>;
    interface ArraySchema<N = any> extends AnySchema {
        items<T extends mappedSchema>(type: T): ArraySchema<extractType<T>>;
    }
    interface ObjectSchema<N = any> extends AnySchema {
        keys<T extends mappedSchemaMap>(schema: T): ObjectSchema<extractMap<N & T>>;
    }
    function object<T extends mappedSchemaMap>(schema: T): ObjectSchema<extractMap<T>>;
    interface FunctionSchema<N = any> extends AnySchema {
    }
    function func<T extends Function>(): FunctionSchema<T>;
    interface AlternativesSchema<T1 extends mappedSchema = never, T2 extends mappedSchema = never, T3 extends mappedSchema = never, T4 extends mappedSchema = never, T5 extends mappedSchema = never> extends AnySchema {
    }
    function alternatives<T1 extends mappedSchema, T2 extends mappedSchema, T3 extends mappedSchema, T4 extends mappedSchema, T5 extends mappedSchema>(a: T1, b: T2, c: T3, d: T4, e: T5): AlternativesSchema<extractType<T1>, extractType<T2>, extractType<T3>, extractType<T4>, extractType<T5>>;
    function alternatives<T1 extends mappedSchema, T2 extends mappedSchema, T3 extends mappedSchema, T4 extends mappedSchema>(a: T1, b: T2, c: T3, d: T4): AlternativesSchema<extractType<T1>, extractType<T2>, extractType<T3>, extractType<T4>>;
    function alternatives<T1 extends mappedSchema, T2 extends mappedSchema, T3 extends mappedSchema>(a: T1, b: T2, c: T3): AlternativesSchema<extractType<T1>, extractType<T2>, extractType<T3>>;
    function alternatives<T1 extends mappedSchema, T2 extends mappedSchema>(a: T1, b: T2): AlternativesSchema<extractType<T1>, extractType<T2>>;
    type extractMap<T> = {
        [K in keyof T]: extractType<T[K]>;
    };
    type extractType<T extends mappedSchema> = T extends primitiveType ? T : T extends BooleanSchema ? boolean : T extends StringSchema<infer O> ? O : T extends NumberSchema ? number : T extends DateSchema ? Date : T extends FunctionSchema<infer O> ? O : 
    /** Holds the extracted type */
    T extends ArraySchema<infer O> ? O[] : T extends ObjectSchema<infer O> ? O : T extends mappedSchemaMap<infer O> ? O : 
    /**
     * Supports Joi.alternatives(Schema1, schema2, ...5)
     *
     * I think there is a better way of writing this,
     * but couldn't find it at the moment.
     */
    T extends AlternativesSchema<infer O1, infer O2, infer O3, infer O4, infer O5> ? O1 | O2 | O3 | O4 | O5 : T extends AlternativesSchema<infer O1, infer O2, infer O3, infer O4> ? O1 | O2 | O3 | O4 : T extends AlternativesSchema<infer O1, infer O2, infer O3> ? O1 | O2 | O3 : T extends AlternativesSchema<infer O1, infer O2> ? O1 | O2 : 
    /**
     * Hack to support [Schema1, Schema2, ...N] alternatives notation
     *
     * Can't use extractType because of cycles:
     * ```
     * T extends Array<infer O> ? extractType<O> :
     *                            ^ cycle
     * ```
     *
     * So one option was to dupplicate extractType here.
     * Im sure we could write it without these dupplication,
     * but some aliasing techinique would be necessary to
     * allow the cycling
     *
     * It is ugly but acctualy works well
     */
    T extends Array<infer O> ? (O extends primitiveType ? O : O extends BooleanSchema ? boolean : O extends StringSchema<infer O> ? O : O extends NumberSchema ? number : O extends DateSchema ? Date : O extends FunctionSchema<infer O> ? O : O extends ArraySchema<infer O> ? O[] : O extends ObjectSchema<infer O> ? O : O extends mappedSchemaMap<infer O> ? O : O extends AlternativesSchema<infer O1, infer O2, infer O3, infer O4, infer O5> ? O1 | O2 | O3 | O4 | O5 : O extends AlternativesSchema<infer O1, infer O2, infer O3, infer O4> ? O1 | O2 | O3 | O4 : O extends AlternativesSchema<infer O1, infer O2, infer O3> ? O1 | O2 | O3 : O extends AlternativesSchema<infer O1, infer O2> ? O1 | O2 : any) : any;
}
