Skip to content

Commit a4e76c8

Browse files
authored
fix(form-core): handle numeric keys as array index only if parent is an array (#993)
1 parent 46d9269 commit a4e76c8

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

packages/form-core/src/utils.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ export function setBy(obj: any, _path: any, updater: Updater<any>) {
4949

5050
const key = path.shift()
5151

52-
if (typeof key === 'string') {
52+
if (
53+
typeof key === 'string' ||
54+
(typeof key === 'number' && !Array.isArray(parent))
55+
) {
5356
if (typeof parent === 'object') {
5457
if (parent === null) {
5558
parent = {}
@@ -64,7 +67,7 @@ export function setBy(obj: any, _path: any, updater: Updater<any>) {
6467
}
6568
}
6669

67-
if (Array.isArray(parent) && key !== undefined) {
70+
if (Array.isArray(parent) && typeof key === 'number') {
6871
const prefix = parent.slice(0, key)
6972
return [
7073
...(prefix.length ? prefix : new Array(key)),

packages/form-core/tests/FieldApi.spec.ts

+23
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,29 @@ describe('field api', () => {
485485
])
486486
})
487487

488+
it('should add a field when the key is numeric but the parent is not an array', () => {
489+
const form = new FormApi({
490+
defaultValues: {
491+
items: {} as Record<number, { quantity: number }>,
492+
},
493+
})
494+
495+
const field = new FieldApi({
496+
form,
497+
name: 'items.2.quantity',
498+
})
499+
500+
field.setValue(10)
501+
502+
expect(form.state.values).toStrictEqual({
503+
items: {
504+
2: {
505+
quantity: 10,
506+
},
507+
},
508+
})
509+
})
510+
488511
it('should not throw errors when no meta info is stored on a field and a form re-renders', async () => {
489512
const form = new FormApi({
490513
defaultValues: {

packages/form-core/tests/utils.spec.ts

+23
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ describe('setBy', () => {
6565
setBy(structure, 'kids[0].hobbies[1]', 'gaming').kids[0].hobbies[1],
6666
).toBe('gaming')
6767
})
68+
69+
it("should create an object if it doesn't exist", () => {
70+
expect(setBy(structure, 'father.name', 'John').father.name).toBe('John')
71+
})
72+
73+
it('should create an array if it doesnt exist', () => {
74+
expect(setBy(structure, 'kids[2].name', 'John').kids[2].name).toBe('John')
75+
})
76+
77+
it('should set a value in an object if the key is a number but the parent is an object', () => {
78+
const newStructure = setBy(structure, '5.name', 'John')
79+
expect(newStructure['5'].name).toBe('John')
80+
expect(newStructure).toStrictEqual({ ...structure, 5: { name: 'John' } })
81+
})
82+
83+
it('should set a value in an array if the key is a number and the parent is an array', () => {
84+
const newStructure = setBy(structure, 'kids.2.name', 'John')
85+
expect(newStructure.kids[2].name).toBe('John')
86+
expect(newStructure).toStrictEqual({
87+
...structure,
88+
kids: [...structure.kids, { name: 'John' }],
89+
})
90+
})
6891
})
6992

7093
describe('deleteBy', () => {

0 commit comments

Comments
 (0)