diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index 77174199c..258a540da 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -2136,12 +2136,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 d824bb6a8..09fbf87c4 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -3639,3 +3639,88 @@ it('should mark sourceMap as undefined when async field error is resolved', asyn expect(field.getMeta().errorSourceMap.onChange).toBeUndefined() }) + +it('should reset nested object 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 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: '', + nested: { + field: { + name: '', + }, + }, + } + + const form = new FormApi({ + defaultState: { values: state }, + }) + 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') +}) 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' + >() +})