Skip to content

Commit 9ed9be6

Browse files
authored
fix: extract form error type from global error (#1535)
1 parent 488e3a7 commit 9ed9be6

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

packages/form-core/src/FormApi.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import type {
2929
FieldApi,
3030
} from './FieldApi'
3131
import type {
32+
ExtractGlobalFormError,
3233
FormValidationError,
3334
FormValidationErrorMap,
3435
UpdateMetaOptions,
@@ -96,7 +97,7 @@ export type FormValidateOrFn<TFormData> =
9697
export type UnwrapFormValidateOrFn<
9798
TValidateOrFn extends undefined | FormValidateOrFn<any>,
9899
> = [TValidateOrFn] extends [FormValidateFn<any>]
99-
? ReturnType<TValidateOrFn>
100+
? ExtractGlobalFormError<ReturnType<TValidateOrFn>>
100101
: [TValidateOrFn] extends [StandardSchemaV1<any, any>]
101102
? Record<string, StandardSchemaV1Issue[]>
102103
: undefined
@@ -148,7 +149,7 @@ export type FormAsyncValidateOrFn<TFormData> =
148149
export type UnwrapFormAsyncValidateOrFn<
149150
TValidateOrFn extends undefined | FormAsyncValidateOrFn<any>,
150151
> = [TValidateOrFn] extends [FormValidateAsyncFn<any>]
151-
? Awaited<ReturnType<TValidateOrFn>>
152+
? ExtractGlobalFormError<Awaited<ReturnType<TValidateOrFn>>>
152153
: [TValidateOrFn] extends [StandardSchemaV1<any, any>]
153154
? Record<string, StandardSchemaV1Issue[]>
154155
: undefined

packages/form-core/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ export type GlobalFormValidationError<TFormData> = {
103103
fields: Partial<Record<DeepKeys<TFormData>, ValidationError>>
104104
}
105105

106+
export type ExtractGlobalFormError<TFormError> =
107+
TFormError extends GlobalFormValidationError<any>
108+
? TFormError['form']
109+
: TFormError
110+
106111
/**
107112
* @private
108113
*/

packages/form-core/tests/FormApi.test-d.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,66 @@ it('should infer full field name union for form.resetField parameters', () => {
303303
'shallow' | 'nested' | 'nested.field' | 'nested.field.name'
304304
>()
305305
})
306+
307+
it('should extract the form error type from a global form error', () => {
308+
type FormData = {
309+
firstName: string
310+
lastName: string
311+
}
312+
313+
const form = new FormApi({
314+
defaultValues: {} as FormData,
315+
validators: {
316+
onMount: () => {
317+
return {
318+
form: 'onMount' as const,
319+
fields: {},
320+
}
321+
},
322+
onChange: () => {
323+
return {
324+
form: 'onChange' as const,
325+
fields: {},
326+
}
327+
},
328+
onChangeAsync: () => {
329+
return Promise.resolve({
330+
form: 'onChangeAsync' as const,
331+
fields: {},
332+
})
333+
},
334+
onBlur: () => {
335+
return {
336+
form: 'onBlur' as const,
337+
fields: {},
338+
}
339+
},
340+
onBlurAsync: () => {
341+
return Promise.resolve('onBlurAsync' as const)
342+
},
343+
},
344+
})
345+
346+
expectTypeOf(form.state.errorMap.onChange).toEqualTypeOf<
347+
'onChange' | 'onChangeAsync' | undefined
348+
>()
349+
350+
expectTypeOf(form.state.errorMap.onMount).toEqualTypeOf<
351+
'onMount' | undefined
352+
>()
353+
354+
expectTypeOf(form.state.errorMap.onBlur).toEqualTypeOf<
355+
'onBlur' | 'onBlurAsync' | undefined
356+
>()
357+
358+
expectTypeOf(form.state.errors).toEqualTypeOf<
359+
(
360+
| 'onMount'
361+
| 'onChange'
362+
| 'onChangeAsync'
363+
| 'onBlur'
364+
| 'onBlurAsync'
365+
| undefined
366+
)[]
367+
>
368+
})

0 commit comments

Comments
 (0)