export type Item = Field | MapForm | ListForm; /* * Fields */ export interface CreateFieldOpts { value: VALUE_TYPE; isEqual?: (a: VALUE_TYPE, b: VALUE_TYPE) => boolean; touched?: boolean; validator?: (value: VALUE_TYPE) => ValidationResult; } export interface Field { readonly value: VALUE_TYPE; readonly touched: boolean; readonly hierarchyTouched: boolean; readonly messages: ValidationMessage[]; readonly maxSeverity: Severity; readonly valid: boolean; readonly maxSeverityOfHierarchy: Severity; readonly hierarchyValid: boolean; setValue(newValue: VALUE_TYPE): Field; setTouched(touched: boolean): Field; getAllMessagesInHierarchy(): ValidationMessage[]; toJS(): VALUE_TYPE; map(mapper: (field: Field) => T): T; } export function createField(opts: CreateFieldOpts): Field; /* * MapForm */ export interface MapFormItems { [path: string]: Item; } export interface CreateMapFormOpts { items?: VALUE_TYPE; touched?: boolean; validator?: (form: VALUE_TYPE) => ValidationResult; } export interface SetTouchedOptions { recurse: boolean; } export interface MapForm { readonly touched: boolean; readonly messages: ValidationMessage[]; readonly maxSeverity: Severity; readonly valid: boolean; readonly maxSeverityOfHierarchy: Severity; readonly hierarchyTouched: boolean; readonly hierarchyValid: boolean; put

(path: P, item: I): UpdatedMapForm get

(path: P): VALUE_TYPE[P]; getIn

>(path: P): NestedValueType; remove

(path: P): MapForm>; reduce(reducer: (acc: R, cur: VALUE_TYPE[keyof VALUE_TYPE], key: keyof VALUE_TYPE) => R, seed: R): R; containsKey(key: keyof VALUE_TYPE): boolean; updateIn

, I extends Item>(path: P, updater: (item: NestedValueType) => I): NestedUpdatedMapForm; setTouched(touched: boolean, opts?: SetTouchedOptions): MapForm; getAllMessagesInHierarchy(): ValidationMessage[]; toJS(): ItemValueType>; } export function createMapForm(opts?: CreateMapFormOpts): MapForm; /* * ListForm */ export interface CreateListFormOpts { items?: VALUE_TYPE; touched?: boolean; validator?: (form: VALUE_TYPE) => ValidationResult; } export interface ListForm { readonly size: number; readonly touched: boolean; readonly messages: ValidationMessage[]; readonly maxSeverity: Severity; readonly valid: boolean; readonly maxSeverityOfHierarchy: Severity; readonly hierarchyTouched: boolean; readonly hierarchyValid: boolean; push(item: VALUE_TYPE[number]): ListForm; insert(index: number, item: VALUE_TYPE[number]): ListForm; set(index: number, item: VALUE_TYPE[number]): ListForm; unshift(item: VALUE_TYPE[number]): ListForm; remove(index: number): ListForm; get(index: number): VALUE_TYPE[number] | undefined; getIn

>(path: P): NestedValueType; updateIn

, I extends Item>(path: P, updater: (item: NestedValueType) => I): NestedUpdatedListForm; setTouched(touched: boolean, opts?: SetTouchedOptions): ListForm; getAllMessagesInHierarchy(): ValidationMessage[]; map(mapper: (item: VALUE_TYPE[number]) => M): M[]; reduce(reducer: (acc: R, cur: VALUE_TYPE[number], index: number) => R, seed: R): R; moveUp(index: number): ListForm; moveDown(index: number): ListForm; toJS(): ItemValueType[]; } export function createListForm(opts: CreateListFormOpts): ListForm; /* * Validation */ export type Severity = 'error' | 'warning' | 'info' | 'ok'; export type ValidationResult = ValidationMessage[] | null | undefined; export interface ValidationMessage { severity: Severity; message?: string; // A JSON path describing the path to the form item. This // field gets automatically populated when calling // getAllMessagesInHierarchy(). path?: string; } export function notBlankValidator(s?: string): ValidationResult; export function alwaysValidValidator(v: any): ValidationResult; export function composeValidators(...validators: ((v: any) => ValidationResult)[]): (v: any) => ValidationResult; /* * Internal Types */ /* * Paths */ type Path = VALUE_TYPE extends MapFormItems ? MapPath : VALUE_TYPE extends Item[] ? ListPath : never; type MapPath = { [Key in keyof VALUE_TYPE]: VALUE_TYPE[Key] extends MapForm ? [Key] | [Key, ...MapPath] : VALUE_TYPE[Key] extends ListForm ? [Key] | [Key, ...ListPath] : [Key] }[keyof VALUE_TYPE]; type ListPath = VALUE_TYPE[number] extends ListForm ? [number] | [number, ...ListPath] : VALUE_TYPE[number] extends MapForm ? [number] | [number, ...MapPath] : [number]; /* * Value Types */ type ItemValueType = I extends Field ? FT : I extends MapForm ? { [Key in keyof MIT]: ItemValueType } : I extends ListForm ? ItemValueType[] : never; type NestedValueType> = BASE_VALUE_TYPE extends MapFormItems ? NestedMapValueType : BASE_VALUE_TYPE extends Item[] ? NestedListValueType : never; type NestedMapValueType> = PATH extends [infer Key, ...infer Rest] ? Key extends string ? BASE_VALUE_TYPE[Key] extends infer Value_Type ? Rest extends [] ? Value_Type : Value_Type extends MapForm ? Rest extends Path ? NestedValueType : never : Value_Type extends ListForm ? Rest extends Path ? NestedValueType : never : never : never : never : never; type NestedListValueType> = PATH extends [number, ...infer Rest] ? BASE_VALUE_TYPE[number] extends infer Value_Type ? Rest extends [] ? Value_Type : Value_Type extends MapForm ? Rest extends Path ? NestedValueType : never : Value_Type extends ListForm ? Rest extends Path ? NestedValueType : never : never : never : never; /* * Updates */ type UpdatedMapForm = MapForm & { [Path in PATH]: I}>; type UpdatedListForm = I extends BASE_VALUE_TYPE[number] ? ListForm : ListForm<(BASE_VALUE_TYPE[number] | I)[]>; type NestedUpdatedMapForm, UPDATED_NESTED_VALUE_TYPE extends Item> = PATH extends [infer Key, ...infer Rest] ? Key extends string ? BASE_VALUE_TYPE[Key] extends infer Value_Type ? Rest extends [] ? UpdatedMapForm : Value_Type extends MapForm ? Rest extends Path ? UpdatedMapForm> : never : Value_Type extends ListForm ? Rest extends Path ? UpdatedMapForm> : never : never : never : never : never; type NestedUpdatedListForm, UPDATED_NESTED_VALUE_TYPE extends Item> = PATH extends [number, ...infer Rest] ? BASE_VALUE_TYPE[number] extends infer Value_Type ? Rest extends [] ? UpdatedListForm : Value_Type extends MapForm ? Rest extends Path ? UpdatedListForm> : never : Value_Type extends ListForm ? Rest extends Path ? UpdatedListForm> : never : never : never : never;