Skip to content

Commit 0ad433e

Browse files
authored
fix: prototype methods being discarded when using setData (#2166)
Currently, when calling setData on a wrapper it will not retain methods on any constructed objects passed in. These methods reside in the prototype which the current logic does not persist across. These changes will ensure that any prototype properties/methods are copied over to the proxied data object. fixes #1851
1 parent 2d618e7 commit 0ad433e

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

src/utils.ts

+16-14
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,22 @@ export const mergeDeep = (
8080
if (!isObject(target) || !isObject(source)) {
8181
return source
8282
}
83-
Object.keys(source).forEach((key) => {
84-
const targetValue = target[key]
85-
const sourceValue = source[key]
86-
87-
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
88-
target[key] = sourceValue
89-
} else if (sourceValue instanceof Date) {
90-
target[key] = sourceValue
91-
} else if (isObject(targetValue) && isObject(sourceValue)) {
92-
target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue)
93-
} else {
94-
target[key] = sourceValue
95-
}
96-
})
83+
Object.keys(source)
84+
.concat(Object.getOwnPropertyNames(Object.getPrototypeOf(source) ?? {}))
85+
.forEach((key) => {
86+
const targetValue = target[key]
87+
const sourceValue = source[key]
88+
89+
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
90+
target[key] = sourceValue
91+
} else if (sourceValue instanceof Date) {
92+
target[key] = sourceValue
93+
} else if (isObject(targetValue) && isObject(sourceValue)) {
94+
target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue)
95+
} else {
96+
target[key] = sourceValue
97+
}
98+
})
9799

98100
return target
99101
}

tests/setData.spec.ts

+32
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,36 @@ describe('setData', () => {
214214
expect(wrapper.vm.value).toBeInstanceOf(Date)
215215
expect(wrapper.vm.value!.toISOString()).toBe('2022-08-11T12:15:54.000Z')
216216
})
217+
218+
it('should retain prototype methods for constructed objects when calling setData', async () => {
219+
const expectedResult = 'success!'
220+
class TestClass {
221+
constructor(readonly name: string) {}
222+
getResult(): string {
223+
return expectedResult
224+
}
225+
}
226+
227+
const wrapper = mount(
228+
defineComponent({
229+
template: '<div/>',
230+
data() {
231+
return { value: new TestClass('test1') }
232+
},
233+
methods: {
234+
getResult() {
235+
return `${this.value.name}: ${this.value.getResult()}`
236+
}
237+
}
238+
})
239+
)
240+
241+
expect(wrapper.vm.getResult()).toStrictEqual(`test1: ${expectedResult}`)
242+
243+
await wrapper.setData({
244+
value: new TestClass('test2')
245+
})
246+
247+
expect(wrapper.vm.getResult()).toStrictEqual(`test2: ${expectedResult}`)
248+
})
217249
})

0 commit comments

Comments
 (0)