import { PropType, Ref } from 'vue-demi';
import * as yup from './yup';

type FirstParameter<T extends (...args: any) => any> = Parameters<T>["length"] extends 0 ? undefined : Parameters<T>[0];
type InitialValueListOrLength<T extends (...args: any) => any> = (undefined extends FirstParameter<T> ? number : 0) | FirstParameter<T>[];
type Expand<T> = T extends object ? T extends infer O ? {
    [K in keyof O]: Expand<O[K]>;
} : never : T;
type ValidateOptions = {
    abortEarly?: boolean;
};
type IfYupVersion1_0_0<Y, N> = keyof yup.Schema extends never ? N : Y;
type YupSchema = IfYupVersion1_0_0<yup.Schema, yup.AnySchema>;
type FieldSchema = YupSchema | (() => YupSchema);
type InnerType<T> = IfYupVersion1_0_0<T[] | undefined, yup.AnySchema<T>>;
type FormsFieldSchema<T> = yup.ArraySchema<InnerType<T>, any> | ((arraySchema: yup.ArraySchema<InnerType<T>, any>) => yup.ArraySchema<InnerType<T>, any>);

type Form = {
    [key: `$${string}`]: never;
    [key: string]: Field<any> | PrivateField<any> | FormsField<(arg: any) => Form> | ((...args: any[]) => any) | Form;
};
type FormPropType<T extends () => Form> = PropType<ReturnType<T> & {
    $key?: number;
}>;
declare class Field<T> {
    private readonly $_valueRef;
    private readonly $_errorRef;
    readonly $label: string;
    constructor(value: T | Ref<T>, schema?: FieldSchema, validateOptions?: ValidateOptions);
    get $value(): T;
    set $value(value: T);
    get $error(): yup.ValidationError | undefined;
    get $errorMessages(): string[];
}
type FieldWithPreferredType<T, U extends T> = Field<T>;
declare class PrivateField<T> extends Field<T> {
    private readonly $_isPrivateField;
}
declare class FormsField<T extends (arg: any) => Form> {
    private readonly $generateFormWithKey;
    private readonly $_formsRef;
    private readonly $_errorRef;
    readonly $label: string;
    constructor(generateForm: T, initialValueListOrLength: InitialValueListOrLength<T>, schema?: FormsFieldSchema<ReturnType<T>>, validateOptions?: ValidateOptions);
    get $forms(): readonly (ReturnType<T> & {
        $key: number;
    })[];
    get $writableForms(): (ReturnType<T> & {
        $key: number;
    })[];
    set $writableForms(value: (ReturnType<T> & {
        $key: number;
    })[]);
    get $error(): yup.ValidationError | undefined;
    get $errorMessages(): string[];
    $initialize(initialValueListOrLength?: InitialValueListOrLength<T>): void;
    $append(...args: undefined extends FirstParameter<T> ? [initialValue?: FirstParameter<T>] : [initialValue: FirstParameter<T>]): void;
    $prepend(...args: undefined extends FirstParameter<T> ? [initialValue?: FirstParameter<T>] : [initialValue: FirstParameter<T>]): void;
    $remove(index: number): void;
}
declare function defineForm<T extends Form>(form: T): T;
/**
 * @template T Pass the type of `$value` explicitly like `ref<T>()`.
 */
declare function field<T>(value: T | Ref<T>, schema?: FieldSchema, validateOptions?: ValidateOptions): Field<T>;
/**
 * @template T Pass the type of `$value` explicitly like `ref<T>()`.
 * @template U Pass the preferred type to be the result of `toObject()`.
 */
declare function field<T, U extends T>(value: T | Ref<T>, schema?: FieldSchema, validateOptions?: ValidateOptions): FieldWithPreferredType<T, U>;
declare function privateField<T>(value: T | Ref<T>, schema?: FieldSchema, validateOptions?: ValidateOptions): PrivateField<T>;
declare function formsField<T extends (arg: any) => Form>(generateForm: T, initialValueListOrLength?: InitialValueListOrLength<T>, schema?: FormsFieldSchema<ReturnType<T>>, validateOptions?: ValidateOptions): FormsField<T>;
declare function isValidForm<T extends Form>(form: T | (T & {
    $key: number;
})): boolean;
type ToObjectOutput<T extends Form> = {
    [K in keyof T as T[K] extends PrivateField<any> | ((...args: any[]) => any) ? never : K]: T[K] extends Form ? ToObjectOutput<T[K]> : T[K] extends FieldWithPreferredType<infer U1, infer U2> ? U2 : T[K] extends FormsField<infer U> ? ToObjectOutput<ReturnType<U>>[] : never;
};
declare function toObject<T extends Form>(form: T | (T & {
    $key: number;
})): Expand<ToObjectOutput<T>>;

export { Form, FormPropType, defineForm, field, formsField, isValidForm, privateField, toObject };
