@tanstack/form-core 0.42.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/cjs/FieldApi.cjs +17 -28
  2. package/dist/cjs/FieldApi.cjs.map +1 -1
  3. package/dist/cjs/FieldApi.d.cts +91 -79
  4. package/dist/cjs/FormApi.cjs +50 -53
  5. package/dist/cjs/FormApi.cjs.map +1 -1
  6. package/dist/cjs/FormApi.d.cts +74 -67
  7. package/dist/cjs/formOptions.cjs.map +1 -1
  8. package/dist/cjs/formOptions.d.cts +2 -3
  9. package/dist/cjs/index.cjs +2 -1
  10. package/dist/cjs/index.cjs.map +1 -1
  11. package/dist/cjs/mergeForm.cjs +33 -9
  12. package/dist/cjs/mergeForm.cjs.map +1 -1
  13. package/dist/cjs/mergeForm.d.cts +2 -3
  14. package/dist/cjs/metaHelper.cjs.map +1 -1
  15. package/dist/cjs/metaHelper.d.cts +2 -3
  16. package/dist/cjs/standardSchemaValidator.cjs +24 -31
  17. package/dist/cjs/standardSchemaValidator.cjs.map +1 -1
  18. package/dist/cjs/standardSchemaValidator.d.cts +24 -4
  19. package/dist/cjs/types.d.cts +15 -27
  20. package/dist/cjs/util-types.d.cts +1 -0
  21. package/dist/cjs/utils.cjs +4 -0
  22. package/dist/cjs/utils.cjs.map +1 -1
  23. package/dist/cjs/utils.d.cts +4 -3
  24. package/dist/esm/FieldApi.d.ts +91 -79
  25. package/dist/esm/FieldApi.js +18 -29
  26. package/dist/esm/FieldApi.js.map +1 -1
  27. package/dist/esm/FormApi.d.ts +74 -67
  28. package/dist/esm/FormApi.js +52 -55
  29. package/dist/esm/FormApi.js.map +1 -1
  30. package/dist/esm/formOptions.d.ts +2 -3
  31. package/dist/esm/formOptions.js.map +1 -1
  32. package/dist/esm/index.js +4 -3
  33. package/dist/esm/mergeForm.d.ts +2 -3
  34. package/dist/esm/mergeForm.js +33 -9
  35. package/dist/esm/mergeForm.js.map +1 -1
  36. package/dist/esm/metaHelper.d.ts +2 -3
  37. package/dist/esm/metaHelper.js.map +1 -1
  38. package/dist/esm/standardSchemaValidator.d.ts +24 -4
  39. package/dist/esm/standardSchemaValidator.js +24 -31
  40. package/dist/esm/standardSchemaValidator.js.map +1 -1
  41. package/dist/esm/types.d.ts +15 -27
  42. package/dist/esm/util-types.d.ts +1 -0
  43. package/dist/esm/utils.d.ts +4 -3
  44. package/dist/esm/utils.js +4 -0
  45. package/dist/esm/utils.js.map +1 -1
  46. package/package.json +2 -2
  47. package/src/FieldApi.ts +803 -273
  48. package/src/FormApi.ts +613 -183
  49. package/src/formOptions.ts +26 -4
  50. package/src/mergeForm.ts +63 -26
  51. package/src/metaHelper.ts +28 -6
  52. package/src/standardSchemaValidator.ts +47 -58
  53. package/src/types.ts +39 -34
  54. package/src/util-types.ts +2 -0
  55. package/src/utils.ts +15 -9
package/src/FormApi.ts CHANGED
@@ -5,17 +5,22 @@ import {
5
5
  getAsyncValidatorArray,
6
6
  getBy,
7
7
  getSyncValidatorArray,
8
+ isGlobalFormValidationError,
8
9
  isNonEmptyArray,
9
10
  setBy,
10
11
  shallow,
11
12
  } from './utils'
12
13
  import {
13
14
  isStandardSchemaValidator,
14
- standardSchemaValidator,
15
+ standardSchemaValidators,
15
16
  } from './standardSchemaValidator'
16
17
  import { metaHelper } from './metaHelper'
17
- import type { StandardSchemaV1 } from './standardSchemaValidator'
18
- import type { FieldApi, FieldMeta, FieldMetaBase } from './FieldApi'
18
+ import type {
19
+ StandardSchemaV1,
20
+ StandardSchemaV1Issue,
21
+ TStandardSchemaValidatorValue,
22
+ } from './standardSchemaValidator'
23
+ import type { AnyFieldMeta, AnyFieldMetaBase, FieldApi } from './FieldApi'
19
24
  import type {
20
25
  FormValidationError,
21
26
  FormValidationErrorMap,
@@ -24,48 +29,90 @@ import type {
24
29
  ValidationError,
25
30
  ValidationErrorMap,
26
31
  ValidationErrorMapKeys,
27
- ValidationSource,
28
- Validator,
29
32
  } from './types'
30
33
  import type { DeepKeys, DeepValue } from './util-types'
31
34
  import type { Updater } from './utils'
32
35
 
33
- export type FieldsErrorMapFromValidator<TFormData> = Partial<
34
- Record<DeepKeys<TFormData>, ValidationErrorMap>
36
+ /**
37
+ * @private
38
+ */
39
+ // TODO: Add the `Unwrap` type to the errors
40
+ type FormErrorMapFromValidator<
41
+ TFormData,
42
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
43
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
44
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
45
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
46
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
47
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
48
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
49
+ > = Partial<
50
+ Record<
51
+ DeepKeys<TFormData>,
52
+ ValidationErrorMap<
53
+ TOnMount,
54
+ TOnChange,
55
+ TOnChangeAsync,
56
+ TOnBlur,
57
+ TOnBlurAsync,
58
+ TOnSubmit,
59
+ TOnSubmitAsync
60
+ >
61
+ >
35
62
  >
36
63
 
37
- export type FormValidateFn<
38
- TFormData,
39
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
40
- > = (props: {
64
+ export type FormValidateFn<TFormData> = (props: {
41
65
  value: TFormData
42
- formApi: FormApi<TFormData, TFormValidator>
43
- }) => FormValidationError<TFormData>
66
+ formApi: FormApi<
67
+ TFormData,
68
+ // This is technically an edge-type; which we try to keep non-`any`, but in this case
69
+ // It's referring to an inaccessible type from the field validate function inner types, so it's not a big deal
70
+ any,
71
+ any,
72
+ any,
73
+ any,
74
+ any,
75
+ any,
76
+ any,
77
+ any
78
+ >
79
+ }) => unknown
44
80
 
45
81
  /**
46
82
  * @private
47
83
  */
48
- export type FormValidateOrFn<
49
- TFormData,
50
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
51
- > =
52
- TFormValidator extends Validator<TFormData, infer TFN>
53
- ? TFN | FormValidateFn<TFormData, TFormValidator>
54
- :
55
- | FormValidateFn<TFormData, TFormValidator>
56
- | StandardSchemaV1<TFormData, unknown>
84
+ export type FormValidateOrFn<TFormData> =
85
+ | FormValidateFn<TFormData>
86
+ | StandardSchemaV1<TFormData, unknown>
87
+
88
+ export type UnwrapFormValidateOrFn<
89
+ TValidateOrFn extends undefined | FormValidateOrFn<any>,
90
+ > = [TValidateOrFn] extends [FormValidateFn<any>]
91
+ ? ReturnType<TValidateOrFn>
92
+ : [TValidateOrFn] extends [StandardSchemaV1<any, any>]
93
+ ? Record<string, StandardSchemaV1Issue[]>
94
+ : undefined
57
95
 
58
96
  /**
59
97
  * @private
60
98
  */
61
- export type FormValidateAsyncFn<
62
- TFormData,
63
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
64
- > = (props: {
99
+ export type FormValidateAsyncFn<TFormData> = (props: {
65
100
  value: TFormData
66
- formApi: FormApi<TFormData, TFormValidator>
101
+ formApi: FormApi<
102
+ TFormData,
103
+ // This is technically an edge-type; which we try to keep non-`any`, but in this case
104
+ // It's referring to an inaccessible type from the field validate function inner types, so it's not a big deal
105
+ any,
106
+ any,
107
+ any,
108
+ any,
109
+ any,
110
+ any,
111
+ any,
112
+ any
113
+ >
67
114
  signal: AbortSignal
68
- }) => FormValidationError<TFormData> | Promise<FormValidationError<TFormData>>
115
+ }) => unknown | Promise<unknown>
69
116
 
70
117
  export type FormValidator<TFormData, TType, TFn = unknown> = {
71
118
  validate(options: { value: TType }, fn: TFn): ValidationError
@@ -85,32 +132,40 @@ type ValidationPromiseResult<TFormData> =
85
132
  /**
86
133
  * @private
87
134
  */
88
- export type FormAsyncValidateOrFn<
89
- TFormData,
90
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
91
- > =
92
- TFormValidator extends Validator<TFormData, infer FFN>
93
- ? FFN | FormValidateAsyncFn<TFormData, TFormValidator>
94
- :
95
- | FormValidateAsyncFn<TFormData, TFormValidator>
96
- | StandardSchemaV1<TFormData, unknown>
135
+ export type FormAsyncValidateOrFn<TFormData> =
136
+ | FormValidateAsyncFn<TFormData>
137
+ | StandardSchemaV1<TFormData, unknown>
138
+
139
+ export type UnwrapFormAsyncValidateOrFn<
140
+ TValidateOrFn extends undefined | FormAsyncValidateOrFn<any>,
141
+ > = [TValidateOrFn] extends [FormValidateAsyncFn<any>]
142
+ ? Awaited<ReturnType<TValidateOrFn>>
143
+ : [TValidateOrFn] extends [StandardSchemaV1<any, any>]
144
+ ? Record<string, StandardSchemaV1Issue[]>
145
+ : undefined
97
146
 
98
147
  export interface FormValidators<
99
148
  TFormData,
100
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
149
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
150
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
151
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
152
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
153
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
154
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
155
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
101
156
  > {
102
157
  /**
103
158
  * Optional function that fires as soon as the component mounts.
104
159
  */
105
- onMount?: FormValidateOrFn<TFormData, TFormValidator>
160
+ onMount?: TOnMount
106
161
  /**
107
162
  * Optional function that checks the validity of your data whenever a value changes
108
163
  */
109
- onChange?: FormValidateOrFn<TFormData, TFormValidator>
164
+ onChange?: TOnChange
110
165
  /**
111
166
  * Optional onChange asynchronous counterpart to onChange. Useful for more complex validation logic that might involve server requests.
112
167
  */
113
- onChangeAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>
168
+ onChangeAsync?: TOnChangeAsync
114
169
  /**
115
170
  * The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds.
116
171
  */
@@ -118,17 +173,17 @@ export interface FormValidators<
118
173
  /**
119
174
  * Optional function that validates the form data when a field loses focus, returns a `FormValidationError`
120
175
  */
121
- onBlur?: FormValidateOrFn<TFormData, TFormValidator>
176
+ onBlur?: TOnBlur
122
177
  /**
123
178
  * Optional onBlur asynchronous validation method for when a field loses focus returns a ` FormValidationError` or a promise of `Promise<FormValidationError>`
124
179
  */
125
- onBlurAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>
180
+ onBlurAsync?: TOnBlurAsync
126
181
  /**
127
182
  * The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds.
128
183
  */
129
184
  onBlurAsyncDebounceMs?: number
130
- onSubmit?: FormValidateOrFn<TFormData, TFormValidator>
131
- onSubmitAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>
185
+ onSubmit?: TOnSubmit
186
+ onSubmitAsync?: TOnSubmitAsync
132
187
  }
133
188
 
134
189
  /**
@@ -136,11 +191,38 @@ export interface FormValidators<
136
191
  */
137
192
  export interface FormTransform<
138
193
  TFormData,
139
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
194
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
195
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
196
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
197
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
198
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
199
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
200
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
201
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
140
202
  > {
141
203
  fn: (
142
- formBase: FormApi<TFormData, TFormValidator>,
143
- ) => FormApi<TFormData, TFormValidator>
204
+ formBase: FormApi<
205
+ TFormData,
206
+ TOnMount,
207
+ TOnChange,
208
+ TOnChangeAsync,
209
+ TOnBlur,
210
+ TOnBlurAsync,
211
+ TOnSubmit,
212
+ TOnSubmitAsync,
213
+ TOnServer
214
+ >,
215
+ ) => FormApi<
216
+ TFormData,
217
+ TOnMount,
218
+ TOnChange,
219
+ TOnChangeAsync,
220
+ TOnBlur,
221
+ TOnBlurAsync,
222
+ TOnSubmit,
223
+ TOnSubmitAsync,
224
+ TOnServer
225
+ >
144
226
  deps: unknown[]
145
227
  }
146
228
 
@@ -149,7 +231,14 @@ export interface FormTransform<
149
231
  */
150
232
  export interface FormOptions<
151
233
  TFormData,
152
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
234
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
235
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
236
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
237
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
238
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
239
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
240
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
241
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
153
242
  > {
154
243
  /**
155
244
  * Set initial values for your form.
@@ -158,7 +247,19 @@ export interface FormOptions<
158
247
  /**
159
248
  * The default state for the form.
160
249
  */
161
- defaultState?: Partial<FormState<TFormData>>
250
+ defaultState?: Partial<
251
+ FormState<
252
+ TFormData,
253
+ TOnMount,
254
+ TOnChange,
255
+ TOnChangeAsync,
256
+ TOnBlur,
257
+ TOnBlurAsync,
258
+ TOnSubmit,
259
+ TOnSubmitAsync,
260
+ TOnServer
261
+ >
262
+ >
162
263
  /**
163
264
  * If true, always run async validation, even when sync validation has produced an error. Defaults to undefined.
164
265
  */
@@ -167,29 +268,64 @@ export interface FormOptions<
167
268
  * Optional time in milliseconds if you want to introduce a delay before firing off an async action.
168
269
  */
169
270
  asyncDebounceMs?: number
170
- /**
171
- * A validator adapter to support usage of extra validation types (IE: Zod, Yup, or Valibot usage)
172
- */
173
- validatorAdapter?: TFormValidator
174
271
  /**
175
272
  * A list of validators to pass to the form
176
273
  */
177
- validators?: FormValidators<TFormData, TFormValidator>
274
+ validators?: FormValidators<
275
+ TFormData,
276
+ TOnMount,
277
+ TOnChange,
278
+ TOnChangeAsync,
279
+ TOnBlur,
280
+ TOnBlurAsync,
281
+ TOnSubmit,
282
+ TOnSubmitAsync
283
+ >
178
284
  /**
179
285
  * A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise<any>`
180
286
  */
181
287
  onSubmit?: (props: {
182
288
  value: TFormData
183
- formApi: FormApi<TFormData, TFormValidator>
289
+ formApi: FormApi<
290
+ TFormData,
291
+ TOnMount,
292
+ TOnChange,
293
+ TOnChangeAsync,
294
+ TOnBlur,
295
+ TOnBlurAsync,
296
+ TOnSubmit,
297
+ TOnSubmitAsync,
298
+ TOnServer
299
+ >
184
300
  }) => any | Promise<any>
185
301
  /**
186
302
  * Specify an action for scenarios where the user tries to submit an invalid form.
187
303
  */
188
304
  onSubmitInvalid?: (props: {
189
305
  value: TFormData
190
- formApi: FormApi<TFormData, TFormValidator>
306
+ formApi: FormApi<
307
+ TFormData,
308
+ TOnMount,
309
+ TOnChange,
310
+ TOnChangeAsync,
311
+ TOnBlur,
312
+ TOnBlurAsync,
313
+ TOnSubmit,
314
+ TOnSubmitAsync,
315
+ TOnServer
316
+ >
191
317
  }) => void
192
- transform?: FormTransform<TFormData, TFormValidator>
318
+ transform?: FormTransform<
319
+ TFormData,
320
+ TOnMount,
321
+ TOnChange,
322
+ TOnChangeAsync,
323
+ TOnBlur,
324
+ TOnBlurAsync,
325
+ TOnSubmit,
326
+ TOnSubmitAsync,
327
+ TOnServer
328
+ >
193
329
  }
194
330
 
195
331
  /**
@@ -205,18 +341,29 @@ export type ValidationMeta = {
205
341
  /**
206
342
  * An object representing the field information for a specific field within the form.
207
343
  */
208
- export type FieldInfo<
209
- TFormData,
210
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
211
- > = {
344
+ export type FieldInfo<TFormData> = {
212
345
  /**
213
346
  * An instance of the FieldAPI.
214
347
  */
215
348
  instance: FieldApi<
216
349
  TFormData,
217
350
  any,
218
- Validator<unknown, unknown> | undefined,
219
- TFormValidator
351
+ any,
352
+ any,
353
+ any,
354
+ any,
355
+ any,
356
+ any,
357
+ any,
358
+ any,
359
+ any,
360
+ any,
361
+ any,
362
+ any,
363
+ any,
364
+ any,
365
+ any,
366
+ any
220
367
  > | null
221
368
  /**
222
369
  * A record of field validation internal handling.
@@ -227,7 +374,17 @@ export type FieldInfo<
227
374
  /**
228
375
  * An object representing the current state of the form.
229
376
  */
230
- export type BaseFormState<TFormData> = {
377
+ export type BaseFormState<
378
+ TFormData,
379
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
380
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
381
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
382
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
383
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
384
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
385
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
386
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
387
+ > = {
231
388
  /**
232
389
  * The current values of the form fields.
233
390
  */
@@ -235,7 +392,16 @@ export type BaseFormState<TFormData> = {
235
392
  /**
236
393
  * The error map for the form itself.
237
394
  */
238
- errorMap: FormValidationErrorMap
395
+ errorMap: FormValidationErrorMap<
396
+ UnwrapFormValidateOrFn<TOnMount>,
397
+ UnwrapFormValidateOrFn<TOnChange>,
398
+ UnwrapFormAsyncValidateOrFn<TOnChangeAsync>,
399
+ UnwrapFormValidateOrFn<TOnBlur>,
400
+ UnwrapFormAsyncValidateOrFn<TOnBlurAsync>,
401
+ UnwrapFormValidateOrFn<TOnSubmit>,
402
+ UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>,
403
+ UnwrapFormAsyncValidateOrFn<TOnServer>
404
+ >
239
405
  /**
240
406
  * An internal mechanism used for keeping track of validation logic in a form.
241
407
  */
@@ -243,7 +409,7 @@ export type BaseFormState<TFormData> = {
243
409
  /**
244
410
  * A record of field metadata for each field in the form, not including the derived properties, like `errors` and such
245
411
  */
246
- fieldMetaBase: Record<DeepKeys<TFormData>, FieldMetaBase>
412
+ fieldMetaBase: Record<DeepKeys<TFormData>, AnyFieldMetaBase>
247
413
  /**
248
414
  * A boolean indicating if the form is currently in the process of being submitted after `handleSubmit` is called.
249
415
  *
@@ -271,7 +437,17 @@ export type BaseFormState<TFormData> = {
271
437
  submissionAttempts: number
272
438
  }
273
439
 
274
- export type DerivedFormState<TFormData> = {
440
+ export type DerivedFormState<
441
+ TFormData,
442
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
443
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
444
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
445
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
446
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
447
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
448
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
449
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
450
+ > = {
275
451
  /**
276
452
  * A boolean indicating if the form is currently validating.
277
453
  */
@@ -283,7 +459,16 @@ export type DerivedFormState<TFormData> = {
283
459
  /**
284
460
  * The error array for the form itself.
285
461
  */
286
- errors: ValidationError[]
462
+ errors: Array<
463
+ | UnwrapFormValidateOrFn<TOnMount>
464
+ | UnwrapFormValidateOrFn<TOnChange>
465
+ | UnwrapFormAsyncValidateOrFn<TOnChangeAsync>
466
+ | UnwrapFormValidateOrFn<TOnBlur>
467
+ | UnwrapFormAsyncValidateOrFn<TOnBlurAsync>
468
+ | UnwrapFormValidateOrFn<TOnSubmit>
469
+ | UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>
470
+ | UnwrapFormAsyncValidateOrFn<TOnServer>
471
+ >
287
472
  /**
288
473
  * A boolean indicating if any of the form fields are currently validating.
289
474
  */
@@ -319,15 +504,89 @@ export type DerivedFormState<TFormData> = {
319
504
  /**
320
505
  * A record of field metadata for each field in the form.
321
506
  */
322
- fieldMeta: Record<DeepKeys<TFormData>, FieldMeta>
507
+ fieldMeta: Record<DeepKeys<TFormData>, AnyFieldMeta>
323
508
  }
324
509
 
325
- export type FormState<TFormData> = BaseFormState<TFormData> &
326
- DerivedFormState<TFormData>
510
+ export type FormState<
511
+ TFormData,
512
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
513
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
514
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
515
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
516
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
517
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
518
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
519
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
520
+ > = BaseFormState<
521
+ TFormData,
522
+ TOnMount,
523
+ TOnChange,
524
+ TOnChangeAsync,
525
+ TOnBlur,
526
+ TOnBlurAsync,
527
+ TOnSubmit,
528
+ TOnSubmitAsync,
529
+ TOnServer
530
+ > &
531
+ DerivedFormState<
532
+ TFormData,
533
+ TOnMount,
534
+ TOnChange,
535
+ TOnChangeAsync,
536
+ TOnBlur,
537
+ TOnBlurAsync,
538
+ TOnSubmit,
539
+ TOnSubmitAsync,
540
+ TOnServer
541
+ >
542
+
543
+ export type AnyFormState = FormState<
544
+ any,
545
+ any,
546
+ any,
547
+ any,
548
+ any,
549
+ any,
550
+ any,
551
+ any,
552
+ any
553
+ >
327
554
 
328
- function getDefaultFormState<TFormData>(
329
- defaultState: Partial<FormState<TFormData>>,
330
- ): BaseFormState<TFormData> {
555
+ function getDefaultFormState<
556
+ TFormData,
557
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
558
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
559
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
560
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
561
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
562
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
563
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
564
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
565
+ >(
566
+ defaultState: Partial<
567
+ FormState<
568
+ TFormData,
569
+ TOnMount,
570
+ TOnChange,
571
+ TOnChangeAsync,
572
+ TOnBlur,
573
+ TOnBlurAsync,
574
+ TOnSubmit,
575
+ TOnSubmitAsync,
576
+ TOnServer
577
+ >
578
+ >,
579
+ ): BaseFormState<
580
+ TFormData,
581
+ TOnMount,
582
+ TOnChange,
583
+ TOnChangeAsync,
584
+ TOnBlur,
585
+ TOnBlurAsync,
586
+ TOnSubmit,
587
+ TOnSubmitAsync,
588
+ TOnServer
589
+ > {
331
590
  return {
332
591
  values: defaultState.values ?? ({} as never),
333
592
  errorMap: defaultState.errorMap ?? {},
@@ -346,11 +605,12 @@ function getDefaultFormState<TFormData>(
346
605
  }
347
606
  }
348
607
 
349
- const isFormValidationError = (
350
- error: unknown,
351
- ): error is FormValidationError<unknown> => {
352
- return typeof error === 'object'
353
- }
608
+ /**
609
+ * @public
610
+ *
611
+ * A type representing the Form API with all generics set to `any` for convenience.
612
+ */
613
+ export type AnyFormApi = FormApi<any, any, any, any, any, any, any, any, any>
354
614
 
355
615
  /**
356
616
  * A class representing the Form API. It handles the logic and interactions with the form state.
@@ -361,20 +621,60 @@ const isFormValidationError = (
361
621
  */
362
622
  export class FormApi<
363
623
  TFormData,
364
- TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
624
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
625
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
626
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
627
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
628
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
629
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
630
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
631
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
365
632
  > {
366
633
  /**
367
634
  * The options for the form.
368
635
  */
369
- options: FormOptions<TFormData, TFormValidator> = {}
370
- baseStore!: Store<BaseFormState<TFormData>>
371
- fieldMetaDerived!: Derived<Record<DeepKeys<TFormData>, FieldMeta>>
372
- store!: Derived<FormState<TFormData>>
636
+ options: FormOptions<
637
+ TFormData,
638
+ TOnMount,
639
+ TOnChange,
640
+ TOnChangeAsync,
641
+ TOnBlur,
642
+ TOnBlurAsync,
643
+ TOnSubmit,
644
+ TOnSubmitAsync,
645
+ TOnServer
646
+ > = {}
647
+ baseStore!: Store<
648
+ BaseFormState<
649
+ TFormData,
650
+ TOnMount,
651
+ TOnChange,
652
+ TOnChangeAsync,
653
+ TOnBlur,
654
+ TOnBlurAsync,
655
+ TOnSubmit,
656
+ TOnSubmitAsync,
657
+ TOnServer
658
+ >
659
+ >
660
+ fieldMetaDerived!: Derived<Record<DeepKeys<TFormData>, AnyFieldMeta>>
661
+ store!: Derived<
662
+ FormState<
663
+ TFormData,
664
+ TOnMount,
665
+ TOnChange,
666
+ TOnChangeAsync,
667
+ TOnBlur,
668
+ TOnBlurAsync,
669
+ TOnSubmit,
670
+ TOnSubmitAsync,
671
+ TOnServer
672
+ >
673
+ >
373
674
  /**
374
675
  * A record of field information for each field in the form.
375
676
  */
376
- fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, TFormValidator>> =
377
- {} as any
677
+ fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>> = {} as any
378
678
 
379
679
  get state() {
380
680
  return this.store.state
@@ -388,7 +688,19 @@ export class FormApi<
388
688
  /**
389
689
  * Constructs a new `FormApi` instance with the given form options.
390
690
  */
391
- constructor(opts?: FormOptions<TFormData, TFormValidator>) {
691
+ constructor(
692
+ opts?: FormOptions<
693
+ TFormData,
694
+ TOnMount,
695
+ TOnChange,
696
+ TOnChangeAsync,
697
+ TOnBlur,
698
+ TOnBlurAsync,
699
+ TOnSubmit,
700
+ TOnSubmitAsync,
701
+ TOnServer
702
+ >,
703
+ ) {
392
704
  this.baseStore = new Store(
393
705
  getDefaultFormState({
394
706
  ...(opts?.defaultState as any),
@@ -401,24 +713,35 @@ export class FormApi<
401
713
  deps: [this.baseStore],
402
714
  fn: ({ prevDepVals, currDepVals, prevVal: _prevVal }) => {
403
715
  const prevVal = _prevVal as
404
- | Record<DeepKeys<TFormData>, FieldMeta>
716
+ | Record<DeepKeys<TFormData>, AnyFieldMeta>
405
717
  | undefined
406
718
  const prevBaseStore = prevDepVals?.[0]
407
719
  const currBaseStore = currDepVals[0]
408
720
 
409
721
  let originalMetaCount = 0
410
722
 
411
- const fieldMeta = {} as FormState<TFormData>['fieldMeta']
723
+ const fieldMeta = {} as FormState<
724
+ TFormData,
725
+ TOnMount,
726
+ TOnChange,
727
+ TOnChangeAsync,
728
+ TOnBlur,
729
+ TOnBlurAsync,
730
+ TOnSubmit,
731
+ TOnSubmitAsync,
732
+ TOnServer
733
+ >['fieldMeta']
734
+
412
735
  for (const fieldName of Object.keys(
413
736
  currBaseStore.fieldMetaBase,
414
737
  ) as Array<keyof typeof currBaseStore.fieldMetaBase>) {
415
738
  const currBaseVal = currBaseStore.fieldMetaBase[
416
739
  fieldName as never
417
- ] as FieldMetaBase
740
+ ] as AnyFieldMetaBase
418
741
 
419
742
  const prevBaseVal = prevBaseStore?.fieldMetaBase[
420
743
  fieldName as never
421
- ] as FieldMetaBase | undefined
744
+ ] as AnyFieldMetaBase | undefined
422
745
 
423
746
  const prevFieldInfo =
424
747
  prevVal?.[fieldName as never as keyof typeof prevVal]
@@ -427,11 +750,20 @@ export class FormApi<
427
750
  if (!prevBaseVal || currBaseVal.errorMap !== prevBaseVal.errorMap) {
428
751
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
429
752
  fieldErrors = Object.values(currBaseVal.errorMap ?? {}).filter(
430
- (val: unknown) => val !== undefined,
431
- )
753
+ (val) => val !== undefined,
754
+ ) as never
755
+
756
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
757
+ const fieldInstance = this.getFieldInfo(fieldName)?.instance
758
+
759
+ if (fieldInstance && !fieldInstance.options.disableErrorFlat) {
760
+ fieldErrors = (fieldErrors as undefined | string[])?.flat(
761
+ 1,
762
+ ) as never
763
+ }
432
764
  }
433
765
 
434
- // As a primitive, we don't need to aggressively persist the same referencial value for performance reasons
766
+ // As a primitive, we don't need to aggressively persist the same referential value for performance reasons
435
767
  const isFieldPristine = !currBaseVal.isDirty
436
768
 
437
769
  if (
@@ -449,7 +781,7 @@ export class FormApi<
449
781
  ...currBaseVal,
450
782
  errors: fieldErrors,
451
783
  isPristine: isFieldPristine,
452
- } as FieldMeta
784
+ } as AnyFieldMeta
453
785
  }
454
786
 
455
787
  if (
@@ -466,13 +798,25 @@ export class FormApi<
466
798
  this.store = new Derived({
467
799
  deps: [this.baseStore, this.fieldMetaDerived],
468
800
  fn: ({ prevDepVals, currDepVals, prevVal: _prevVal }) => {
469
- const prevVal = _prevVal as FormState<TFormData> | undefined
801
+ const prevVal = _prevVal as
802
+ | FormState<
803
+ TFormData,
804
+ TOnMount,
805
+ TOnChange,
806
+ TOnChangeAsync,
807
+ TOnBlur,
808
+ TOnBlurAsync,
809
+ TOnSubmit,
810
+ TOnSubmitAsync,
811
+ TOnServer
812
+ >
813
+ | undefined
470
814
  const prevBaseStore = prevDepVals?.[0]
471
815
  const currBaseStore = currDepVals[0]
472
816
 
473
817
  // Computed state
474
818
  const fieldMetaValues = Object.values(currBaseStore.fieldMetaBase) as (
475
- | FieldMeta
819
+ | AnyFieldMeta
476
820
  | undefined
477
821
  )[]
478
822
 
@@ -511,21 +855,27 @@ export class FormApi<
511
855
  !prevBaseStore ||
512
856
  currBaseStore.errorMap !== prevBaseStore.errorMap
513
857
  ) {
514
- errors = Object.values(currBaseStore.errorMap).reduce(
515
- (prev, curr) => {
516
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
517
- if (curr === undefined) return prev
518
- if (typeof curr === 'string') {
519
- prev.push(curr)
520
- return prev
521
- } else if (curr && isFormValidationError(curr)) {
522
- prev.push(curr.form)
523
- return prev
524
- }
858
+ errors = Object.values(currBaseStore.errorMap).reduce<
859
+ Array<
860
+ | UnwrapFormValidateOrFn<TOnMount>
861
+ | UnwrapFormValidateOrFn<TOnChange>
862
+ | UnwrapFormAsyncValidateOrFn<TOnChangeAsync>
863
+ | UnwrapFormValidateOrFn<TOnBlur>
864
+ | UnwrapFormAsyncValidateOrFn<TOnBlurAsync>
865
+ | UnwrapFormValidateOrFn<TOnSubmit>
866
+ | UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>
867
+ | UnwrapFormAsyncValidateOrFn<TOnServer>
868
+ >
869
+ >((prev, curr) => {
870
+ if (curr === undefined) return prev
871
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
872
+ if (curr && isGlobalFormValidationError(curr)) {
873
+ prev.push(curr.form as never)
525
874
  return prev
526
- },
527
- [] as ValidationError[],
528
- )
875
+ }
876
+ prev.push(curr as never)
877
+ return prev
878
+ }, [])
529
879
  }
530
880
 
531
881
  const isFormValid = errors.length === 0
@@ -578,7 +928,17 @@ export class FormApi<
578
928
  isBlurred,
579
929
  isPristine,
580
930
  isDirty,
581
- } as FormState<TFormData>
931
+ } as FormState<
932
+ TFormData,
933
+ TOnMount,
934
+ TOnChange,
935
+ TOnChangeAsync,
936
+ TOnBlur,
937
+ TOnBlurAsync,
938
+ TOnSubmit,
939
+ TOnSubmitAsync,
940
+ TOnServer
941
+ >
582
942
 
583
943
  // Only run transform if state has shallowly changed - IE how React.useEffect works
584
944
  const transformArray = this.options.transform?.deps ?? []
@@ -605,35 +965,25 @@ export class FormApi<
605
965
  * @private
606
966
  */
607
967
  runValidator<
608
- TValue extends {
609
- value: TFormData
610
- formApi: FormApi<any, any>
611
- validationSource: ValidationSource
968
+ TValue extends TStandardSchemaValidatorValue<TFormData> & {
969
+ formApi: AnyFormApi
612
970
  },
613
971
  TType extends 'validate' | 'validateAsync',
614
972
  >(props: {
615
973
  validate: TType extends 'validate'
616
- ? FormValidateOrFn<TFormData, TFormValidator>
617
- : FormAsyncValidateOrFn<TFormData, TFormValidator>
974
+ ? FormValidateOrFn<TFormData>
975
+ : FormAsyncValidateOrFn<TFormData>
618
976
  value: TValue
619
977
  type: TType
620
- }): ReturnType<ReturnType<Validator<any>>[TType]> {
621
- const adapter = this.options.validatorAdapter
622
- if (
623
- adapter &&
624
- (typeof props.validate !== 'function' || '~standard' in props.validate)
625
- ) {
626
- return adapter()[props.type](props.value, props.validate) as never
627
- }
628
-
978
+ }): unknown {
629
979
  if (isStandardSchemaValidator(props.validate)) {
630
- return standardSchemaValidator()()[props.type](
980
+ return standardSchemaValidators[props.type](
631
981
  props.value,
632
982
  props.validate,
633
983
  ) as never
634
984
  }
635
985
 
636
- return (props.validate as FormValidateFn<any, any>)(props.value) as never
986
+ return (props.validate as FormValidateFn<any>)(props.value) as never
637
987
  }
638
988
 
639
989
  mount = () => {
@@ -653,7 +1003,19 @@ export class FormApi<
653
1003
  /**
654
1004
  * Updates the form options and form state.
655
1005
  */
656
- update = (options?: FormOptions<TFormData, TFormValidator>) => {
1006
+ update = (
1007
+ options?: FormOptions<
1008
+ TFormData,
1009
+ TOnMount,
1010
+ TOnChange,
1011
+ TOnChangeAsync,
1012
+ TOnBlur,
1013
+ TOnBlurAsync,
1014
+ TOnSubmit,
1015
+ TOnSubmitAsync,
1016
+ TOnServer
1017
+ >,
1018
+ ) => {
657
1019
  if (!options) return
658
1020
 
659
1021
  const oldOptions = this.options
@@ -728,24 +1090,24 @@ export class FormApi<
728
1090
  validateAllFields = async (cause: ValidationCause) => {
729
1091
  const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any
730
1092
  batch(() => {
731
- void (
732
- Object.values(this.fieldInfo) as FieldInfo<any, TFormValidator>[]
733
- ).forEach((field) => {
734
- if (!field.instance) return
735
- const fieldInstance = field.instance
736
- // Validate the field
737
- fieldValidationPromises.push(
738
- // Remember, `validate` is either a sync operation or a promise
739
- Promise.resolve().then(() =>
740
- fieldInstance.validate(cause, { skipFormValidation: true }),
741
- ),
742
- )
743
- // If any fields are not touched
744
- if (!field.instance.state.meta.isTouched) {
745
- // Mark them as touched
746
- field.instance.setMeta((prev) => ({ ...prev, isTouched: true }))
747
- }
748
- })
1093
+ void (Object.values(this.fieldInfo) as FieldInfo<any>[]).forEach(
1094
+ (field) => {
1095
+ if (!field.instance) return
1096
+ const fieldInstance = field.instance
1097
+ // Validate the field
1098
+ fieldValidationPromises.push(
1099
+ // Remember, `validate` is either a sync operation or a promise
1100
+ Promise.resolve().then(() =>
1101
+ fieldInstance.validate(cause, { skipFormValidation: true }),
1102
+ ),
1103
+ )
1104
+ // If any fields are not touched
1105
+ if (!field.instance.state.meta.isTouched) {
1106
+ // Mark them as touched
1107
+ field.instance.setMeta((prev) => ({ ...prev, isTouched: true }))
1108
+ }
1109
+ },
1110
+ )
749
1111
  })
750
1112
 
751
1113
  const fieldErrorMapMap = await Promise.all(fieldValidationPromises)
@@ -819,12 +1181,30 @@ export class FormApi<
819
1181
  cause: ValidationCause,
820
1182
  ): {
821
1183
  hasErrored: boolean
822
- fieldsErrorMap: FieldsErrorMapFromValidator<TFormData>
1184
+ fieldsErrorMap: FormErrorMapFromValidator<
1185
+ TFormData,
1186
+ TOnMount,
1187
+ TOnChange,
1188
+ TOnChangeAsync,
1189
+ TOnBlur,
1190
+ TOnBlurAsync,
1191
+ TOnSubmit,
1192
+ TOnSubmitAsync
1193
+ >
823
1194
  } => {
824
1195
  const validates = getSyncValidatorArray(cause, this.options)
825
1196
  let hasErrored = false as boolean
826
1197
 
827
- const fieldsErrorMap: FieldsErrorMapFromValidator<TFormData> = {}
1198
+ const fieldsErrorMap: FormErrorMapFromValidator<
1199
+ TFormData,
1200
+ TOnMount,
1201
+ TOnChange,
1202
+ TOnChangeAsync,
1203
+ TOnBlur,
1204
+ TOnBlurAsync,
1205
+ TOnSubmit,
1206
+ TOnSubmitAsync
1207
+ > = {}
828
1208
 
829
1209
  batch(() => {
830
1210
  for (const validateObj of validates) {
@@ -910,7 +1290,18 @@ export class FormApi<
910
1290
  */
911
1291
  validateAsync = async (
912
1292
  cause: ValidationCause,
913
- ): Promise<FieldsErrorMapFromValidator<TFormData>> => {
1293
+ ): Promise<
1294
+ FormErrorMapFromValidator<
1295
+ TFormData,
1296
+ TOnMount,
1297
+ TOnChange,
1298
+ TOnChangeAsync,
1299
+ TOnBlur,
1300
+ TOnBlurAsync,
1301
+ TOnSubmit,
1302
+ TOnSubmitAsync
1303
+ >
1304
+ > => {
914
1305
  const validates = getAsyncValidatorArray(cause, this.options)
915
1306
 
916
1307
  if (!this.state.isFormValidating) {
@@ -928,6 +1319,7 @@ export class FormApi<
928
1319
  | undefined
929
1320
 
930
1321
  for (const validateObj of validates) {
1322
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
931
1323
  if (!validateObj.validate) continue
932
1324
  const key = getErrorMapKey(validateObj.cause)
933
1325
  const fieldValidatorMeta = this.state.validationMetaMap[key]
@@ -1009,7 +1401,16 @@ export class FormApi<
1009
1401
 
1010
1402
  let results: ValidationPromiseResult<TFormData>[] = []
1011
1403
 
1012
- const fieldsErrorMap: FieldsErrorMapFromValidator<TFormData> = {}
1404
+ const fieldsErrorMap: FormErrorMapFromValidator<
1405
+ TFormData,
1406
+ TOnMount,
1407
+ TOnChange,
1408
+ TOnChangeAsync,
1409
+ TOnBlur,
1410
+ TOnBlurAsync,
1411
+ TOnSubmit,
1412
+ TOnSubmitAsync
1413
+ > = {}
1013
1414
  if (promises.length) {
1014
1415
  results = await Promise.all(promises)
1015
1416
  for (const fieldValidationResult of results) {
@@ -1045,8 +1446,28 @@ export class FormApi<
1045
1446
  validate = (
1046
1447
  cause: ValidationCause,
1047
1448
  ):
1048
- | FieldsErrorMapFromValidator<TFormData>
1049
- | Promise<FieldsErrorMapFromValidator<TFormData>> => {
1449
+ | FormErrorMapFromValidator<
1450
+ TFormData,
1451
+ TOnMount,
1452
+ TOnChange,
1453
+ TOnChangeAsync,
1454
+ TOnBlur,
1455
+ TOnBlurAsync,
1456
+ TOnSubmit,
1457
+ TOnSubmitAsync
1458
+ >
1459
+ | Promise<
1460
+ FormErrorMapFromValidator<
1461
+ TFormData,
1462
+ TOnMount,
1463
+ TOnChange,
1464
+ TOnChangeAsync,
1465
+ TOnBlur,
1466
+ TOnBlurAsync,
1467
+ TOnSubmit,
1468
+ TOnSubmitAsync
1469
+ >
1470
+ > => {
1050
1471
  // Attempt to sync validate first
1051
1472
  const { hasErrored, fieldsErrorMap } = this.validateSync(cause)
1052
1473
 
@@ -1103,14 +1524,14 @@ export class FormApi<
1103
1524
  }
1104
1525
 
1105
1526
  batch(() => {
1106
- void (
1107
- Object.values(this.fieldInfo) as FieldInfo<TFormData, TFormValidator>[]
1108
- ).forEach((field) => {
1109
- field.instance?.options.listeners?.onSubmit?.({
1110
- value: field.instance.state.value,
1111
- fieldApi: field.instance,
1112
- })
1113
- })
1527
+ void (Object.values(this.fieldInfo) as FieldInfo<TFormData>[]).forEach(
1528
+ (field) => {
1529
+ field.instance?.options.listeners?.onSubmit?.({
1530
+ value: field.instance.state.value,
1531
+ fieldApi: field.instance,
1532
+ })
1533
+ },
1534
+ )
1114
1535
  })
1115
1536
 
1116
1537
  try {
@@ -1139,7 +1560,7 @@ export class FormApi<
1139
1560
  */
1140
1561
  getFieldMeta = <TField extends DeepKeys<TFormData>>(
1141
1562
  field: TField,
1142
- ): FieldMeta | undefined => {
1563
+ ): AnyFieldMeta | undefined => {
1143
1564
  return this.state.fieldMeta[field]
1144
1565
  }
1145
1566
 
@@ -1148,7 +1569,7 @@ export class FormApi<
1148
1569
  */
1149
1570
  getFieldInfo = <TField extends DeepKeys<TFormData>>(
1150
1571
  field: TField,
1151
- ): FieldInfo<TFormData, TFormValidator> => {
1572
+ ): FieldInfo<TFormData> => {
1152
1573
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1153
1574
  return (this.fieldInfo[field] ||= {
1154
1575
  instance: null,
@@ -1167,7 +1588,7 @@ export class FormApi<
1167
1588
  */
1168
1589
  setFieldMeta = <TField extends DeepKeys<TFormData>>(
1169
1590
  field: TField,
1170
- updater: Updater<FieldMeta>,
1591
+ updater: Updater<AnyFieldMeta>,
1171
1592
  ) => {
1172
1593
  this.baseStore.setState((prev) => {
1173
1594
  return {
@@ -1184,10 +1605,10 @@ export class FormApi<
1184
1605
  }
1185
1606
 
1186
1607
  resetFieldMeta = <TField extends DeepKeys<TFormData>>(
1187
- fieldMeta: Record<TField, FieldMeta>,
1188
- ): Record<TField, FieldMeta> => {
1608
+ fieldMeta: Record<TField, AnyFieldMeta>,
1609
+ ): Record<TField, AnyFieldMeta> => {
1189
1610
  return Object.keys(fieldMeta).reduce(
1190
- (acc: Record<TField, FieldMeta>, key) => {
1611
+ (acc: Record<TField, AnyFieldMeta>, key) => {
1191
1612
  const fieldKey = key as TField
1192
1613
  acc[fieldKey] = {
1193
1614
  isValidating: false,
@@ -1200,7 +1621,7 @@ export class FormApi<
1200
1621
  }
1201
1622
  return acc
1202
1623
  },
1203
- {} as Record<TField, FieldMeta>,
1624
+ {} as Record<TField, AnyFieldMeta>,
1204
1625
  )
1205
1626
  }
1206
1627
 
@@ -1422,14 +1843,27 @@ export class FormApi<
1422
1843
  /**
1423
1844
  * Updates the form's errorMap
1424
1845
  */
1425
- setErrorMap(errorMap: ValidationErrorMap) {
1426
- this.baseStore.setState((prev) => ({
1427
- ...prev,
1428
- errorMap: {
1429
- ...prev.errorMap,
1430
- ...errorMap,
1431
- },
1432
- }))
1846
+ setErrorMap(
1847
+ errorMap: ValidationErrorMap<
1848
+ TOnMount,
1849
+ TOnChange,
1850
+ TOnChangeAsync,
1851
+ TOnBlur,
1852
+ TOnBlurAsync,
1853
+ TOnSubmit,
1854
+ TOnSubmitAsync
1855
+ >,
1856
+ ) {
1857
+ this.baseStore.setState(
1858
+ (prev) =>
1859
+ ({
1860
+ ...prev,
1861
+ errorMap: {
1862
+ ...prev.errorMap,
1863
+ ...errorMap,
1864
+ },
1865
+ }) as never,
1866
+ )
1433
1867
  }
1434
1868
  }
1435
1869
 
@@ -1438,16 +1872,12 @@ function normalizeError<TFormData>(rawError?: FormValidationError<unknown>): {
1438
1872
  fieldErrors?: Partial<Record<DeepKeys<TFormData>, ValidationError>>
1439
1873
  } {
1440
1874
  if (rawError) {
1441
- if (typeof rawError === 'object') {
1875
+ if (isGlobalFormValidationError(rawError)) {
1442
1876
  const formError = normalizeError(rawError.form).formError
1443
1877
  const fieldErrors = rawError.fields
1444
1878
  return { formError, fieldErrors } as never
1445
1879
  }
1446
1880
 
1447
- if (typeof rawError !== 'string') {
1448
- return { formError: 'Invalid Form Values' }
1449
- }
1450
-
1451
1881
  return { formError: rawError }
1452
1882
  }
1453
1883