testElement.dispatchEvent(new CustomEvent('foobar'))
expect(fn2).toHaveBeenCalledTimes(1)
})
+
+ it('handles an unknown type', () => {
+ const el = document.createElement('div')
+ patchProp(el, 'onClick', null, 'test')
+ el.dispatchEvent(new Event('click'))
+ expect(
+ '[Vue warn]: Wrong type passed to the event invoker, ' +
+ 'did you maybe forget @ or : in front of your prop?' +
+ '\nReceived onClick="test"',
+ ).toHaveBeenWarned()
+ })
})
-import { hyphenate, isArray } from '@vue/shared'
+import { NOOP, hyphenate, isArray, isFunction, isString } from '@vue/shared'
import {
type ComponentInternalInstance,
ErrorCodes,
callWithAsyncErrorHandling,
+ warn,
} from '@vue/runtime-core'
interface Invoker extends EventListener {
el: Element & { [veiKey]?: Record<string, Invoker | undefined> },
rawName: string,
prevValue: EventValue | null,
- nextValue: EventValue | null,
+ nextValue: EventValue | unknown,
instance: ComponentInternalInstance | null = null,
) {
// vei = vue event invokers
const existingInvoker = invokers[rawName]
if (nextValue && existingInvoker) {
// patch
- existingInvoker.value = nextValue
+ existingInvoker.value = __DEV__
+ ? sanitizeEventValue(nextValue, rawName)
+ : (nextValue as EventValue)
} else {
const [name, options] = parseName(rawName)
if (nextValue) {
// add
- const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
+ const invoker = (invokers[rawName] = createInvoker(
+ __DEV__
+ ? sanitizeEventValue(nextValue, rawName)
+ : (nextValue as EventValue),
+ instance,
+ ))
addEventListener(el, name, invoker, options)
} else if (existingInvoker) {
// remove
return invoker
}
+function sanitizeEventValue(value: unknown, propName: string): EventValue {
+ if (isFunction(value) || isArray(value)) {
+ return value as EventValue
+ }
+ warn(
+ `Wrong type passed to the event invoker, did you maybe forget @ or : ` +
+ `in front of your prop?\nReceived ` +
+ `${propName}=${isString(value) ? JSON.stringify(value) : `[${typeof value}]`}`,
+ )
+ return NOOP
+}
+
function patchStopImmediatePropagation(
e: Event,
value: EventValue,
originalStop.call(e)
;(e as any)._stopped = true
}
- return value.map(fn => (e: Event) => !(e as any)._stopped && fn && fn(e))
+ return (value as Function[]).map(
+ fn => (e: Event) => !(e as any)._stopped && fn && fn(e),
+ )
} else {
return value
}