From 3e99f6f950c0172657ccd85fed6b7184c331f8a2 Mon Sep 17 00:00:00 2001 From: LeCarbonator <18158911+LeCarbonator@users.noreply.github.com> Date: Fri, 9 May 2025 10:50:29 +0200 Subject: [PATCH 1/3] fix(form-core): fix form.resetField() ignoring nested fields --- packages/form-core/src/FormApi.ts | 9 ++-- packages/form-core/tests/FormApi.spec.ts | 58 ++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index f7762b40d..a7b541ebb 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -2109,12 +2109,9 @@ export class FormApi< ...prev.fieldMetaBase, [field]: defaultFieldMeta, }, - values: { - ...prev.values, - [field]: - this.options.defaultValues && - this.options.defaultValues[field as keyof TFormData], - }, + values: this.options.defaultValues + ? setBy(prev.values, field, getBy(this.options.defaultValues, field)) + : prev.values, } }) } diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index ac151676a..583ae9014 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -3580,3 +3580,61 @@ it('should mark sourceMap as undefined when async field error is resolved', asyn expect(field.getMeta().errorSourceMap.onChange).toBeUndefined() }) + +it('should reset nested fields', () => { + const defaultValues = { + shallow: '', + nested: { + field: { + name: '', + }, + }, + } + + const form = new FormApi({ + defaultValues, + }) + form.mount() + + form.setFieldValue('shallow', 'Shallow') + form.setFieldValue('nested.field.name', 'Nested') + + expect(form.state.values.shallow).toEqual('Shallow') + expect(form.state.values.nested.field.name).toEqual('Nested') + + form.resetField('shallow') + expect(form.state.values.shallow).toEqual('') + + form.resetField('nested.field.name') + expect(form.state.values.nested.field.name).toEqual('') +}) + +it('should preserve nested fields on resetField if defaultValues is not provided', () => { + const defaultValues = { + shallow: '', + nested: { + field: { + name: '', + }, + }, + } + + const form = new FormApi({ + defaultState: { + values: defaultValues, + }, + }) + form.mount() + + form.setFieldValue('shallow', 'Shallow') + form.setFieldValue('nested.field.name', 'Nested') + + expect(form.state.values.shallow).toEqual('Shallow') + expect(form.state.values.nested.field.name).toEqual('Nested') + + form.resetField('shallow') + expect(form.state.values.shallow).toEqual('Shallow') + + form.resetField('nested.field.name') + expect(form.state.values.nested.field.name).toEqual('Nested') +}) From 0b768c4dabe16fadeff9eab03df6d96b0b162872 Mon Sep 17 00:00:00 2001 From: LeCarbonator <18158911+LeCarbonator@users.noreply.github.com> Date: Tue, 13 May 2025 07:07:19 +0200 Subject: [PATCH 2/3] chore: rename unit test variable for clarity --- packages/form-core/tests/FormApi.spec.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index 583ae9014..9abd77d44 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -3610,7 +3610,7 @@ it('should reset nested fields', () => { }) it('should preserve nested fields on resetField if defaultValues is not provided', () => { - const defaultValues = { + const state = { shallow: '', nested: { field: { @@ -3620,9 +3620,7 @@ it('should preserve nested fields on resetField if defaultValues is not provided } const form = new FormApi({ - defaultState: { - values: defaultValues, - }, + defaultState: { values: state }, }) form.mount() From d1d007aec38a4525a1a0490a795dd6ba0a0103ad Mon Sep 17 00:00:00 2001 From: Harry Whorlow Date: Sat, 17 May 2025 10:37:27 +0200 Subject: [PATCH 3/3] chore: test-d and array test --- packages/form-core/tests/FormApi.spec.ts | 31 +++++++++++++++++++++- packages/form-core/tests/FormApi.test-d.ts | 30 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index 0dedb9c03..09fbf87c4 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -3640,7 +3640,7 @@ it('should mark sourceMap as undefined when async field error is resolved', asyn expect(field.getMeta().errorSourceMap.onChange).toBeUndefined() }) -it('should reset nested fields', () => { +it('should reset nested object fields', () => { const defaultValues = { shallow: '', nested: { @@ -3668,6 +3668,35 @@ it('should reset nested fields', () => { expect(form.state.values.nested.field.name).toEqual('') }) +it('should reset nested array fields', () => { + const defaultValues = { + shallow: '', + nested: { + arr: [{ name: '' }, { test: 'array-test' }], + }, + } + + const form = new FormApi({ + defaultValues, + }) + form.mount() + + form.setFieldValue('shallow', 'Shallow') + form.setFieldValue('nested.arr[0].name', 'nested-arr') + form.setFieldValue('nested.arr[1].test', 'array-test-changed') + + expect(form.state.values.shallow).toEqual('Shallow') + expect(form.state.values.nested.arr[0]?.name).toEqual('nested-arr') + expect(form.state.values.nested.arr[1]?.test).toEqual('array-test-changed') + + form.resetField('shallow') + expect(form.state.values.shallow).toEqual('') + + form.resetField('nested.arr[0].name') + expect(form.state.values.nested.arr[0]?.name).toEqual('') + expect(form.state.values.nested.arr[1]?.test).toEqual('array-test-changed') +}) + it('should preserve nested fields on resetField if defaultValues is not provided', () => { const state = { shallow: '', diff --git a/packages/form-core/tests/FormApi.test-d.ts b/packages/form-core/tests/FormApi.test-d.ts index 473be0715..cdb979a20 100644 --- a/packages/form-core/tests/FormApi.test-d.ts +++ b/packages/form-core/tests/FormApi.test-d.ts @@ -273,3 +273,33 @@ it('should only allow array fields for array-specific methods', () => { // @ts-expect-error too wide! const validate3 = form.validateArrayFieldsStartingFrom }) + +it('should infer full field name union for form.resetField parameters', () => { + type FormData = { + shallow: string + nested: { + field: { + name: string + } + } + } + + const defaultValue = { + shallow: '', + nested: { + field: { + name: '', + }, + }, + } + + const form = new FormApi({ + defaultValues: defaultValue as FormData, + }) + + expectTypeOf(form.resetField) + .parameter(0) + .toEqualTypeOf< + 'shallow' | 'nested' | 'nested.field' | 'nested.field.name' + >() +})