diff --git a/examples/react/field-errors-from-form-validators/src/index.tsx b/examples/react/field-errors-from-form-validators/src/index.tsx
index ace86f45b..bd200068d 100644
--- a/examples/react/field-errors-from-form-validators/src/index.tsx
+++ b/examples/react/field-errors-from-form-validators/src/index.tsx
@@ -112,8 +112,7 @@ export default function App() {
errorMap.onSubmit ? (
- There was an error on the form:{' '}
- {errorMap.onSubmit?.toString()}
+ There was an error on the form: {errorMap.onSubmit.toString()}
) : null
diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts
index 7624b7c7a..d7aeb309c 100644
--- a/packages/form-core/src/FieldApi.ts
+++ b/packages/form-core/src/FieldApi.ts
@@ -1671,17 +1671,24 @@ export class FieldApi<
/**
* Updates the field's errorMap
*/
- setErrorMap(errorMap: ValidationErrorMap) {
- this.setMeta(
- (prev) =>
- ({
- ...prev,
- errorMap: {
- ...prev.errorMap,
- ...errorMap,
- },
- }) as never,
- )
+ setErrorMap(
+ errorMap: ValidationErrorMap<
+ UnwrapFieldValidateOrFn,
+ UnwrapFieldValidateOrFn,
+ UnwrapFieldAsyncValidateOrFn,
+ UnwrapFieldValidateOrFn,
+ UnwrapFieldAsyncValidateOrFn,
+ UnwrapFieldValidateOrFn,
+ UnwrapFieldAsyncValidateOrFn
+ >,
+ ) {
+ this.setMeta((prev) => ({
+ ...prev,
+ errorMap: {
+ ...prev.errorMap,
+ ...errorMap,
+ },
+ }))
}
/**
diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts
index cfd292e46..2181daa25 100644
--- a/packages/form-core/src/FormApi.ts
+++ b/packages/form-core/src/FormApi.ts
@@ -2123,25 +2123,23 @@ export class FormApi<
*/
setErrorMap(
errorMap: ValidationErrorMap<
- TOnMount,
- TOnChange,
- TOnChangeAsync,
- TOnBlur,
- TOnBlurAsync,
- TOnSubmit,
- TOnSubmitAsync
+ UnwrapFormValidateOrFn,
+ UnwrapFormValidateOrFn,
+ UnwrapFormAsyncValidateOrFn,
+ UnwrapFormValidateOrFn,
+ UnwrapFormAsyncValidateOrFn,
+ UnwrapFormValidateOrFn,
+ UnwrapFormAsyncValidateOrFn,
+ UnwrapFormAsyncValidateOrFn
>,
) {
- this.baseStore.setState(
- (prev) =>
- ({
- ...prev,
- errorMap: {
- ...prev.errorMap,
- ...errorMap,
- },
- }) as never,
- )
+ this.baseStore.setState((prev) => ({
+ ...prev,
+ errorMap: {
+ ...prev.errorMap,
+ ...errorMap,
+ },
+ }))
}
/**
diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts
index 11fe57c5a..01cd7eb77 100644
--- a/packages/form-core/tests/FieldApi.spec.ts
+++ b/packages/form-core/tests/FieldApi.spec.ts
@@ -1785,9 +1785,7 @@ describe('field api', () => {
name: 'name',
})
nameField.mount()
- nameField.setErrorMap({
- onChange: "name can't be Josh",
- })
+ nameField.setErrorMap({ onChange: "name can't be Josh" as never })
expect(nameField.getMeta().isValid).toBe(false)
expect(nameField.getMeta().errorMap.onChange).toEqual("name can't be Josh")
})
@@ -1802,14 +1800,10 @@ describe('field api', () => {
name: 'name',
})
nameField.mount()
- nameField.setErrorMap({
- onChange: "name can't be Josh",
- })
+ nameField.setErrorMap({ onChange: "name can't be Josh" as never })
expect(nameField.getMeta().isValid).toBe(false)
expect(nameField.getMeta().errorMap.onChange).toEqual("name can't be Josh")
- nameField.setErrorMap({
- onBlur: 'name must begin with uppercase',
- })
+ nameField.setErrorMap({ onBlur: 'name must begin with uppercase' as never })
expect(nameField.getMeta().isValid).toBe(false)
expect(nameField.getMeta().errorMap.onChange).toEqual("name can't be Josh")
expect(nameField.getMeta().errorMap.onBlur).toEqual(
@@ -1827,14 +1821,10 @@ describe('field api', () => {
name: 'name',
})
nameField.mount()
- nameField.setErrorMap({
- onChange: "name can't be Josh",
- })
+ nameField.setErrorMap({ onChange: "name can't be Josh" as never })
expect(nameField.getMeta().isValid).toBe(false)
expect(nameField.getMeta().errorMap.onChange).toEqual("name can't be Josh")
- nameField.setErrorMap({
- onChange: 'other validation error',
- })
+ nameField.setErrorMap({ onChange: 'other validation error' as never })
expect(nameField.getMeta().errorMap.onChange).toEqual(
'other validation error',
)
diff --git a/packages/form-core/tests/FieldApi.test-d.ts b/packages/form-core/tests/FieldApi.test-d.ts
index 97af6d5fd..9c67a8297 100644
--- a/packages/form-core/tests/FieldApi.test-d.ts
+++ b/packages/form-core/tests/FieldApi.test-d.ts
@@ -394,3 +394,67 @@ it('should only have field-level error types returned from parseValueWithSchema
Promise
>()
})
+
+it("should allow setting manual errors according to the validator's return type", () => {
+ const form = new FormApi({
+ defaultValues: {
+ firstName: '',
+ lastName: '',
+ },
+ validators: {
+ onChange: () => {
+ return {
+ fields: {
+ firstName: '123' as const,
+ },
+ }
+ },
+ },
+ })
+
+ const field = new FieldApi({
+ form,
+ name: 'firstName',
+ validators: {
+ onChange: () => 10 as const,
+ onBlur: () => ['onBlur'] as const,
+ },
+ })
+
+ field.setErrorMap({
+ onChange: '123',
+ })
+
+ expectTypeOf(field.setErrorMap).parameter(0).toEqualTypeOf<{
+ onMount: undefined
+ onChange: '123' | 10 | undefined
+ onBlur: readonly ['onBlur'] | undefined
+ onSubmit: undefined
+ onServer: unknown
+ }>
+})
+
+it('should allow setting manual errors with standard schema validators on the field level', () => {
+ const form = new FormApi({
+ defaultValues: {
+ firstName: '',
+ lastName: '',
+ },
+ })
+
+ const field = new FieldApi({
+ form,
+ name: 'firstName',
+ validators: {
+ onChange: z.string(),
+ },
+ })
+
+ expectTypeOf(field.setErrorMap).parameter(0).toEqualTypeOf<{
+ onMount: undefined
+ onChange: { message: string }[] | undefined
+ onBlur: undefined
+ onSubmit: undefined
+ onServer: unknown
+ }>
+})
diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts
index ac151676a..292fce077 100644
--- a/packages/form-core/tests/FormApi.spec.ts
+++ b/packages/form-core/tests/FormApi.spec.ts
@@ -736,7 +736,7 @@ describe('form api', () => {
field2.mount()
field1.handleBlur()
- field1.setErrorMap({ onSubmit: 'test' })
+ field1.setErrorMap({ onSubmit: 'test' as never })
expect(field0.state.meta.isBlurred).toBe(false)
expect(field1.state.meta.isBlurred).toBe(true)
diff --git a/packages/form-core/tests/FormApi.test-d.ts b/packages/form-core/tests/FormApi.test-d.ts
index eb8e4b619..87920ae71 100644
--- a/packages/form-core/tests/FormApi.test-d.ts
+++ b/packages/form-core/tests/FormApi.test-d.ts
@@ -116,3 +116,46 @@ it('should only have form-level error types returned from parseFieldValuesWithSc
Promise
>()
})
+
+it("should allow setting manual errors according to the validator's return type", () => {
+ const form = new FormApi({
+ defaultValues: {
+ firstName: '',
+ lastName: '',
+ },
+ validators: {
+ onChange: () => ['onChange'] as const,
+ onMount: () => 10 as const,
+ onBlur: () => ({ onBlur: true as const, onBlurNumber: 1 }),
+ onSubmit: () => 'onSubmit' as const,
+ onBlurAsync: () => Promise.resolve('onBlurAsync' as const),
+ onChangeAsync: () => Promise.resolve('onChangeAsync' as const),
+ onSubmitAsync: () => Promise.resolve('onSubmitAsync' as const),
+ },
+ })
+
+ expectTypeOf(form.setErrorMap).parameter(0).toEqualTypeOf<{
+ onMount: 10 | undefined
+ onChange: readonly ['onChange'] | 'onChangeAsync' | undefined
+ onBlur: { onBlur: true; onBlurNumber: number } | 'onBlurAsync' | undefined
+ onSubmit: 'onSubmit' | 'onSubmitAsync' | undefined
+ onServer: undefined
+ }>
+})
+
+it('should not allow setting manual errors if no validator is specified', () => {
+ const form = new FormApi({
+ defaultValues: {
+ firstName: '',
+ lastName: '',
+ },
+ })
+
+ expectTypeOf(form.setErrorMap).parameter(0).toEqualTypeOf<{
+ onMount: undefined
+ onChange: undefined
+ onBlur: undefined
+ onSubmit: undefined
+ onServer: undefined
+ }>
+})