/// <reference types="node" />
export type IS<T> = (input?: unknown) => input is T;
export declare function isIS<T>(input?: unknown): input is IS<T>;
export declare function assertIS<T>(input?: unknown): true | never;
export type Fallback<OUTPUT> = (input?: unknown) => OUTPUT | never;
export declare function isFallback<OUTPUT>(input?: unknown): input is Fallback<OUTPUT>;
export declare function assertFallback<OUTPUT>(input?: unknown): true | never;
export type Conversion<INPUT, OUTPUT> = (this: Converter<OUTPUT>, input: INPUT) => OUTPUT;
export declare function isConversion<INPUT, OUTPUT>(input: unknown): input is Conversion<INPUT, OUTPUT>;
export declare function assertConversion<INPUT, OUTPUT>(input: unknown): true | never;
type TypesMap = {
    undefined: undefined;
    boolean: boolean;
    number: number;
    bigint: bigint;
    string: string;
    symbol: symbol;
};
type TypeConversions<OUTPUT> = {
    [Name in keyof TypesMap]: Conversion<TypesMap[Name], OUTPUT>;
};
type TypeConversion<Name, OUTPUT> = Name extends keyof TypeConversions<OUTPUT> ? TypeConversions<OUTPUT>[Name] : never;
/**
 * @description converts input data to specific type
 * - at first checks if conversion is necessary
 * - attempts conversion based on the input data type
 * - searches for suitable conversions among registered
 * - calls a fallback function
 *
 * @example <caption>converter creation</caption>
 * const positive = new Converter(
 *   (input) => typeof input === 'number' && input > 0,
 *   (input) => input === 0 ? 0.1 : 0.2
 * );
 *
 * positive
 *   .undefined(() => 0.3)
 *   .boolean((i) => i ? 1 : 0.4)
 *   .number(function(i) {
 *     const result = Math.abs(i)
 *     return this.is(result) ? result : this.fallback(i);
 *   })
 *   .string((i) => positive.convert(Number(i)))
 *   .symbol((i) => positive.convert(Symbol.keyFor(i)))
 *   .bigint((i) => positive.convert(Number(i)))
 *   .register(Array.isArray, (i) => positive.convert(i[0]))
 *   .register((i) => i === null, (i) => 0.5);
 *
 * positive.convert(1); // 1
 * positive.convert(0); // 0.1 (fallback)
 * positive.convert(NaN); // 0.2 (fallback)
 * positive.convert(undefined); // 0.3 (has own handler)
 * positive.convert(false); // 0.4 (has own handler)
 * positive.convert(null); // 0.5 (has own handler)
 * positive.convert(2n); // 2
 * positive.convert(-3); // 3
 * positive.convert('4'); // 4
 * positive.convert([5, 6]); // 5
 *
 * @example <caption>conversion with prohibited input types</caption>
 * const converter = new Converter(
 *   (input) => typeof input === 'number',
 *   (input) => {
 *     throw new Error('unknown input data type:' + input);
 *   })
 *   .string((i) => {
 *     throw new Error('string input is forbidden:' + i);
 *   })
 *   .boolean(Number)
 *   .register(Array.isArray, (i) => converter.convert(i[0]));
 *
 * converter.convert(true); // 1
 * converter.convert(2); // 2
 * converter.convert('3'); // Error
 * converter.convert([4]); // 4
 * converter.convert(Promise.resolve(5)); // Error
 */
export declare class Converter<OUTPUT> {
    static InvalidTypeCheckFunction: {
        new (message?: string | undefined, value?: unknown, options?: unknown): {
            value?: unknown;
            throw(): void;
            name: string;
            message: string;
            stack?: string | undefined;
        };
        captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
        prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
        stackTraceLimit: number;
    };
    static InvalidFallbackFunction: {
        new (message?: string | undefined, value?: unknown, options?: unknown): {
            value?: unknown;
            throw(): void;
            name: string;
            message: string;
            stack?: string | undefined;
        };
        captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
        prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
        stackTraceLimit: number;
    };
    static InvalidConversionFunction: {
        new (message?: string | undefined, value?: unknown, options?: unknown): {
            value?: unknown;
            throw(): void;
            name: string;
            message: string;
            stack?: string | undefined;
        };
        captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
        prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
        stackTraceLimit: number;
    };
    static InvalidConverter: {
        new (message?: string | undefined, value?: unknown, options?: unknown): {
            value?: unknown;
            throw(): void;
            name: string;
            message: string;
            stack?: string | undefined;
        };
        captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
        prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
        stackTraceLimit: number;
    };
    protected _is: IS<OUTPUT>;
    protected _fallback: Fallback<OUTPUT>;
    protected _types: Partial<TypeConversions<OUTPUT>>;
    protected _conversions: Map<IS<any>, Conversion<any, OUTPUT>>;
    /**
     * @param {IS<OUTPUT>} is - initial input data type check (predicate). determines if any conversion is necessary
     * @param {Fallback<OUTPUT>} fallback - fallback value generator. runs if none of the available conversions are suitable
     */
    constructor(is: IS<OUTPUT>, fallback: Fallback<OUTPUT>);
    get is(): IS<OUTPUT>;
    set is(is: IS<OUTPUT>);
    get fallback(): Fallback<OUTPUT>;
    set fallback(fallback: Fallback<OUTPUT>);
    get types(): Partial<TypeConversions<OUTPUT>>;
    get conversions(): Array<[IS<unknown>, Conversion<unknown, OUTPUT>]>;
    /**
     * @description converts data according to saved conversion rules
     * @param {*} input - input data
     */
    convert: (input?: unknown) => OUTPUT;
    /**
     * @description adds conversion function for `INPUT` type
     * @param {IS<INPUT>} is - input data type check (predicate), determines if input can be processed by `conversion`
     * @param {Conversion<INPUT, OUTPUT>} conversion - `INPUT` to `OUTPUT` conversion function
     */
    register<INPUT>(is: IS<INPUT>, conversion: Conversion<INPUT, OUTPUT>): this;
    /**
     * @description removes conversion for `INPUT` type
     * @param {IS<INPUT>} is - input type check (predicate)
     */
    unregister<INPUT>(is: IS<INPUT>): this;
    /**
     * @description set conversion rule for type `name` if `conversion` is defined or unset if undefined
     * @param {string} name - one of types (`typeof` result)
     * @param {Conversion} [conversion]
     */
    type<Name extends keyof TypesMap>(name: Name, conversion?: TypeConversion<Name, OUTPUT>): this;
    /**
     * @description conversion rule setter for `undefined` input
     * @param {Conversion} [conversion]
     */
    undefined(conversion?: Conversion<undefined, OUTPUT>): this;
    /**
     * @description conversion rule setter for `boolean` input
     * @param {Conversion} [conversion]
     */
    boolean(conversion?: Conversion<boolean, OUTPUT>): this;
    /**
     * @description conversion rule setter for `number` input
     * @param {Conversion} [conversion]
     */
    number(conversion?: Conversion<number, OUTPUT>): this;
    /**
     * @description conversion rule setter for `bigint` input
     * @param {Conversion} [conversion]
     */
    bigint(conversion?: Conversion<bigint, OUTPUT>): this;
    /**
     * @description conversion rule setter for `string` input
     * @param {Conversion} [conversion]
     */
    string(conversion?: Conversion<string, OUTPUT>): this;
    /**
     * @description conversion rule setter for `symbol` input
     * @param {Conversion} [conversion]
     */
    symbol(conversion?: Conversion<symbol, OUTPUT>): this;
    /**
     * @example
     * const converter = new Converter(
     *   (i) => typeof i === 'number',
     *   () => 0
     * )
     *   .undefined(() => 1);
     *
     * const clone = converter
     *   .clone()
     *   .undefined(() => 2);
     *
     * converter.convert(); // 1
     * clone.convert(); // 2
    */
    clone(): Converter<OUTPUT>;
    static build<OUTPUT>(is: IS<OUTPUT>, fallback: Fallback<OUTPUT>, types?: Partial<TypeConversions<OUTPUT>>, conversions?: Iterable<[IS<any>, Conversion<any, OUTPUT>]>): Converter<OUTPUT>;
    static is: (input?: unknown) => boolean;
    static assert(input?: unknown): boolean;
}
export default Converter;
//# sourceMappingURL=Converter.d.ts.map