Skip to content

Commit a7b5f1c

Browse files
committed
feat(props): configured prop argument to readonly
1 parent 40b3232 commit a7b5f1c

File tree

2 files changed

+48
-19
lines changed

2 files changed

+48
-19
lines changed

packages/runtime-core/__tests__/componentProps.spec.ts

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -278,26 +278,54 @@ describe('component props', () => {
278278
expect(root.innerHTML).toBe('<div id="b">2</div>')
279279
})
280280

281-
test('validator arguments', async () => {
282-
const mockFn = jest.fn((...args: any[]) => true)
283-
const Comp = defineComponent({
284-
props: {
285-
foo: {
286-
type: Number,
287-
validator: (value, props) => mockFn(value, props)
281+
describe('validator', () => {
282+
test('validator should be called with two arguments', async () => {
283+
const mockFn = jest.fn((...args: any[]) => true)
284+
const Comp = defineComponent({
285+
props: {
286+
foo: {
287+
type: Number,
288+
validator: (value, props) => mockFn(value, props)
289+
},
290+
bar: {
291+
type: Number
292+
}
288293
},
289-
bar: {
290-
type: Number
291-
}
292-
},
293-
template: `<div />`
294+
template: `<div />`
295+
})
296+
297+
// Note this one is using the main Vue render so it can compile template
298+
// on the fly
299+
const root = document.createElement('div')
300+
domRender(h(Comp, { foo: 1, bar: 2 }), root)
301+
expect(mockFn).toHaveBeenCalledWith(1, { foo: 1, bar: 2 })
294302
})
295303

296-
// Note this one is using the main Vue render so it can compile template
297-
// on the fly
298-
const root = document.createElement('div')
299-
domRender(h(Comp, { foo: 1, bar: 2 }), root)
300-
expect(mockFn).toHaveBeenCalledWith(1, { foo: 1, bar: 2 })
304+
test('validator should not be able to mutate other props', async () => {
305+
const mockFn = jest.fn((...args: any[]) => true)
306+
const Comp = defineComponent({
307+
props: {
308+
foo: {
309+
type: Number,
310+
validator: (value, props) => !!(props.bar = 1)
311+
},
312+
bar: {
313+
type: Number,
314+
validator: value => mockFn(value)
315+
}
316+
},
317+
template: `<div />`
318+
})
319+
320+
// Note this one is using the main Vue render so it can compile template
321+
// on the fly
322+
const root = document.createElement('div')
323+
domRender(h(Comp, { foo: 1, bar: 2 }), root)
324+
expect(
325+
`Set operation on key "bar" failed: target is readonly.`
326+
).toHaveBeenWarnedLast()
327+
expect(mockFn).toHaveBeenCalledWith(2)
328+
})
301329
})
302330

303331
test('warn props mutation', () => {

packages/runtime-core/src/componentProps.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import {
22
toRaw,
33
shallowReactive,
44
trigger,
5-
TriggerOpTypes
5+
TriggerOpTypes,
6+
shallowReadonly
67
} from '@vue/reactivity'
78
import {
89
EMPTY_OBJ,
@@ -575,7 +576,7 @@ function validateProps(
575576
key,
576577
resolvedValues[key],
577578
opt,
578-
resolvedValues
579+
shallowReadonly(resolvedValues),
579580
!hasOwn(rawProps, key) && !hasOwn(rawProps, hyphenate(key))
580581
)
581582
}

0 commit comments

Comments
 (0)