diff --git a/.changeset/healthy-forks-live.md b/.changeset/healthy-forks-live.md new file mode 100644 index 000000000..a4b16ad24 --- /dev/null +++ b/.changeset/healthy-forks-live.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +fix(form-core): prevent runtime errors when using `deleteField` diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index 611941b19..f18a348d3 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -1642,6 +1642,11 @@ export class FormApi< for (const field of Object.keys( this.state.fieldMeta, ) as DeepKeys[]) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (this.baseStore.state.fieldMetaBase[field] === undefined) { + continue + } + const fieldMeta = this.getFieldMeta(field) if (!fieldMeta) continue @@ -1845,6 +1850,11 @@ export class FormApi< for (const field of Object.keys( this.state.fieldMeta, ) as DeepKeys[]) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (this.baseStore.state.fieldMetaBase[field] === undefined) { + continue + } + const fieldMeta = this.getFieldMeta(field) if (!fieldMeta) continue diff --git a/packages/react-form/tests/useForm.test.tsx b/packages/react-form/tests/useForm.test.tsx index d9495ef19..d3a566180 100644 --- a/packages/react-form/tests/useForm.test.tsx +++ b/packages/react-form/tests/useForm.test.tsx @@ -892,4 +892,70 @@ describe('useForm', () => { await user.click(target) expect(result).toHaveTextContent('1') }) + + it('should not error when using deleteField in edge cases', async () => { + function Comp() { + const form = useForm({ + defaultValues: { + firstName: '', + lastName: '', + }, + validators: { + onChange: ({ value }) => { + const fields: Record = {} + + if (value.firstName.length === 0) { + fields.firstName = 'Last Name is required' + } + + return { fields } + }, + }, + }) + + return ( +
{ + e.preventDefault() + form.handleSubmit() + }} + > +

Personal Information

+ ( + field.handleChange(e.target.value)} + /> + )} + /> + ( + field.handleChange(e.target.value)} + /> + )} + /> + + + ) + } + + const { getByTestId } = render() + const removeButton = getByTestId('remove') + const input = getByTestId('input') + + await user.type(input, 'a') + await user.click(removeButton) + }) })