فهرست منبع

Merge branch 'main' into feat/reactiveity-transform-shorthands

Anthony Fu 3 سال پیش
والد
کامیت
d1d594aad3

+ 1 - 1
package.json

@@ -93,7 +93,7 @@
     "todomvc-app-css": "^2.3.0",
     "ts-jest": "^27.0.5",
     "tslib": "^2.4.0",
-    "typescript": "^4.6.4",
+    "typescript": "^4.7.4",
     "vite": "^2.9.8",
     "vue": "workspace:*",
     "yorkie": "^2.0.0"

+ 13 - 7
packages/reactivity/__tests__/readonly.spec.ts

@@ -480,21 +480,27 @@ describe('reactivity/readonly', () => {
     const r = ref(false)
     const ror = readonly(r)
     const obj = reactive({ ror })
-    try {
+    expect(() => {
       obj.ror = true
-    } catch (e) {}
-
+    }).toThrow()
     expect(obj.ror).toBe(false)
   })
+
   test('replacing a readonly ref nested in a reactive object with a new ref', () => {
     const r = ref(false)
     const ror = readonly(r)
     const obj = reactive({ ror })
-    try {
-      obj.ror = ref(true) as unknown as boolean
-    } catch (e) {}
-
+    obj.ror = ref(true) as unknown as boolean
     expect(obj.ror).toBe(true)
     expect(toRaw(obj).ror).not.toBe(ror) // ref successfully replaced
   })
+
+  test('setting readonly object to writable nested ref', () => {
+    const r = ref<any>()
+    const obj = reactive({ r })
+    const ro = readonly({})
+    obj.r = ro
+    expect(obj.r).toBe(ro)
+    expect(r.value).toBe(ro)
+  })
 })

+ 19 - 1
packages/reactivity/__tests__/ref.spec.ts

@@ -10,7 +10,7 @@ import {
 } from '../src/index'
 import { computed } from '@vue/runtime-dom'
 import { shallowRef, unref, customRef, triggerRef } from '../src/ref'
-import { isShallow } from '../src/reactive'
+import { isShallow, readonly, shallowReactive } from '../src/reactive'
 
 describe('reactivity/ref', () => {
   it('should hold a value', () => {
@@ -400,4 +400,22 @@ describe('reactivity/ref', () => {
     b.value = obj
     expect(spy2).toBeCalledTimes(1)
   })
+
+  test('ref should preserve value shallow/readonly-ness', () => {
+    const original = {}
+    const r = reactive(original)
+    const s = shallowReactive(original)
+    const rr = readonly(original)
+    const a = ref(original)
+
+    expect(a.value).toBe(r)
+
+    a.value = s
+    expect(a.value).toBe(s)
+    expect(a.value).not.toBe(r)
+
+    a.value = rr
+    expect(a.value).toBe(rr)
+    expect(a.value).not.toBe(r)
+  })
 })

+ 22 - 0
packages/reactivity/__tests__/shallowReactive.spec.ts

@@ -7,6 +7,7 @@ import {
 } from '../src/reactive'
 
 import { effect } from '../src/effect'
+import { Ref, isRef, ref } from '../src/ref'
 
 describe('shallowReactive', () => {
   test('should not make non-reactive properties reactive', () => {
@@ -46,6 +47,27 @@ describe('shallowReactive', () => {
     expect(isReactive(r.foo.bar)).toBe(false)
   })
 
+  // vuejs/vue#12597
+  test('should not unwrap refs', () => {
+    const foo = shallowReactive({
+      bar: ref(123)
+    })
+    expect(isRef(foo.bar)).toBe(true)
+    expect(foo.bar.value).toBe(123)
+  })
+
+  // vuejs/vue#12688
+  test('should not mutate refs', () => {
+    const original = ref(123)
+    const foo = shallowReactive<{ bar: Ref<number> | number }>({
+      bar: original
+    })
+    expect(foo.bar).toBe(original)
+    foo.bar = 234
+    expect(foo.bar).toBe(234)
+    expect(original.value).toBe(123)
+  })
+
   test('should respect shallow/deep versions of same target on access', () => {
     const original = {}
     const shallow = shallowReactive(original)

+ 3 - 3
packages/reactivity/src/baseHandlers.ts

@@ -158,10 +158,10 @@ function createSetter(shallow = false) {
     if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
       return false
     }
-    if (!shallow && !isReadonly(value)) {
-      if (!isShallow(value)) {
-        value = toRaw(value)
+    if (!shallow) {
+      if (!isShallow(value) && !isReadonly(value)) {
         oldValue = toRaw(oldValue)
+        value = toRaw(value)
       }
       if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
         oldValue.value = value

+ 1 - 1
packages/reactivity/src/computed.ts

@@ -30,7 +30,7 @@ export class ComputedRefImpl<T> {
   public readonly effect: ReactiveEffect<T>
 
   public readonly __v_isRef = true
-  public readonly [ReactiveFlags.IS_READONLY]: boolean
+  public readonly [ReactiveFlags.IS_READONLY]: boolean = false
 
   public _dirty = true
   public _cacheable: boolean

+ 12 - 3
packages/reactivity/src/ref.ts

@@ -6,7 +6,14 @@ import {
 } from './effect'
 import { TrackOpTypes, TriggerOpTypes } from './operations'
 import { isArray, hasChanged, IfAny } from '@vue/shared'
-import { isProxy, toRaw, isReactive, toReactive } from './reactive'
+import {
+  isProxy,
+  toRaw,
+  isReactive,
+  toReactive,
+  isReadonly,
+  isShallow
+} from './reactive'
 import type { ShallowReactiveMarker } from './reactive'
 import { CollectionTypes } from './collectionHandlers'
 import { createDep, Dep } from './dep'
@@ -112,10 +119,12 @@ class RefImpl<T> {
   }
 
   set value(newVal) {
-    newVal = this.__v_isShallow ? newVal : toRaw(newVal)
+    const useDirectValue =
+      this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
+    newVal = useDirectValue ? newVal : toRaw(newVal)
     if (hasChanged(newVal, this._rawValue)) {
       this._rawValue = newVal
-      this._value = this.__v_isShallow ? newVal : toReactive(newVal)
+      this._value = useDirectValue ? newVal : toReactive(newVal)
       triggerRefValue(this, newVal)
     }
   }

+ 3 - 2
packages/runtime-core/__tests__/apiWatch.spec.ts

@@ -509,7 +509,8 @@ describe('api: watch', () => {
     expect(cb).not.toHaveBeenCalled()
   })
 
-  it('should fire on component unmount w/ flush: pre', async () => {
+  // #2291
+  it('should not fire on component unmount w/ flush: pre', async () => {
     const toggle = ref(true)
     const cb = jest.fn()
     const Comp = {
@@ -527,7 +528,7 @@ describe('api: watch', () => {
     expect(cb).not.toHaveBeenCalled()
     toggle.value = false
     await nextTick()
-    expect(cb).toHaveBeenCalledTimes(1)
+    expect(cb).not.toHaveBeenCalled()
   })
 
   // #1763

+ 23 - 71
packages/runtime-core/__tests__/scheduler.spec.ts

@@ -3,9 +3,8 @@ import {
   nextTick,
   queuePostFlushCb,
   invalidateJob,
-  queuePreFlushCb,
-  flushPreFlushCbs,
-  flushPostFlushCbs
+  flushPostFlushCbs,
+  flushPreFlushCbs
 } from '../src/scheduler'
 
 describe('scheduler', () => {
@@ -114,65 +113,7 @@ describe('scheduler', () => {
     })
   })
 
-  describe('queuePreFlushCb', () => {
-    it('basic usage', async () => {
-      const calls: string[] = []
-      const cb1 = () => {
-        calls.push('cb1')
-      }
-      const cb2 = () => {
-        calls.push('cb2')
-      }
-
-      queuePreFlushCb(cb1)
-      queuePreFlushCb(cb2)
-
-      expect(calls).toEqual([])
-      await nextTick()
-      expect(calls).toEqual(['cb1', 'cb2'])
-    })
-
-    it('should dedupe queued preFlushCb', async () => {
-      const calls: string[] = []
-      const cb1 = () => {
-        calls.push('cb1')
-      }
-      const cb2 = () => {
-        calls.push('cb2')
-      }
-      const cb3 = () => {
-        calls.push('cb3')
-      }
-
-      queuePreFlushCb(cb1)
-      queuePreFlushCb(cb2)
-      queuePreFlushCb(cb1)
-      queuePreFlushCb(cb2)
-      queuePreFlushCb(cb3)
-
-      expect(calls).toEqual([])
-      await nextTick()
-      expect(calls).toEqual(['cb1', 'cb2', 'cb3'])
-    })
-
-    it('chained queuePreFlushCb', async () => {
-      const calls: string[] = []
-      const cb1 = () => {
-        calls.push('cb1')
-        // cb2 will be executed after cb1 at the same tick
-        queuePreFlushCb(cb2)
-      }
-      const cb2 = () => {
-        calls.push('cb2')
-      }
-      queuePreFlushCb(cb1)
-
-      await nextTick()
-      expect(calls).toEqual(['cb1', 'cb2'])
-    })
-  })
-
-  describe('queueJob w/ queuePreFlushCb', () => {
+  describe('pre flush jobs', () => {
     it('queueJob inside preFlushCb', async () => {
       const calls: string[] = []
       const job1 = () => {
@@ -183,8 +124,9 @@ describe('scheduler', () => {
         calls.push('cb1')
         queueJob(job1)
       }
+      cb1.pre = true
 
-      queuePreFlushCb(cb1)
+      queueJob(cb1)
       await nextTick()
       expect(calls).toEqual(['cb1', 'job1'])
     })
@@ -194,17 +136,23 @@ describe('scheduler', () => {
       const job1 = () => {
         calls.push('job1')
       }
+      job1.id = 1
+
       const cb1 = () => {
         calls.push('cb1')
         queueJob(job1)
         // cb2 should execute before the job
-        queuePreFlushCb(cb2)
+        queueJob(cb2)
       }
+      cb1.pre = true
+
       const cb2 = () => {
         calls.push('cb2')
       }
+      cb2.pre = true
+      cb2.id = 1
 
-      queuePreFlushCb(cb1)
+      queueJob(cb1)
       await nextTick()
       expect(calls).toEqual(['cb1', 'cb2', 'job1'])
     })
@@ -216,9 +164,9 @@ describe('scheduler', () => {
         // when updating the props of a child component. This is handled
         // directly inside `updateComponentPreRender` to avoid non atomic
         // cb triggers (#1763)
-        queuePreFlushCb(cb1)
-        queuePreFlushCb(cb2)
-        flushPreFlushCbs(undefined, job1)
+        queueJob(cb1)
+        queueJob(cb2)
+        flushPreFlushCbs()
         calls.push('job1')
       }
       const cb1 = () => {
@@ -226,9 +174,11 @@ describe('scheduler', () => {
         // a cb triggers its parent job, which should be skipped
         queueJob(job1)
       }
+      cb1.pre = true
       const cb2 = () => {
         calls.push('cb2')
       }
+      cb2.pre = true
 
       queueJob(job1)
       await nextTick()
@@ -237,12 +187,14 @@ describe('scheduler', () => {
 
     // #3806
     it('queue preFlushCb inside postFlushCb', async () => {
-      const cb = jest.fn()
+      const spy = jest.fn()
+      const cb = () => spy()
+      cb.pre = true
       queuePostFlushCb(() => {
-        queuePreFlushCb(cb)
+        queueJob(cb)
       })
       await nextTick()
-      expect(cb).toHaveBeenCalled()
+      expect(spy).toHaveBeenCalled()
     })
   })
 

+ 3 - 3
packages/runtime-core/src/apiDefineComponent.ts

@@ -103,7 +103,7 @@ export function defineComponent<
   M extends MethodOptions = {},
   Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-  E extends EmitsOptions = EmitsOptions,
+  E extends EmitsOptions = {},
   EE extends string = string
 >(
   options: ComponentOptionsWithoutProps<
@@ -130,7 +130,7 @@ export function defineComponent<
   M extends MethodOptions = {},
   Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-  E extends EmitsOptions = Record<string, any>,
+  E extends EmitsOptions = {},
   EE extends string = string
 >(
   options: ComponentOptionsWithArrayProps<
@@ -168,7 +168,7 @@ export function defineComponent<
   M extends MethodOptions = {},
   Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
   Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-  E extends EmitsOptions = Record<string, any>,
+  E extends EmitsOptions = {},
   EE extends string = string
 >(
   options: ComponentOptionsWithObjectProps<

+ 4 - 2
packages/runtime-core/src/apiWatch.ts

@@ -9,7 +9,7 @@ import {
   EffectScheduler,
   DebuggerOptions
 } from '@vue/reactivity'
-import { SchedulerJob, queuePreFlushCb } from './scheduler'
+import { SchedulerJob, queueJob } from './scheduler'
 import {
   EMPTY_OBJ,
   isObject,
@@ -345,7 +345,9 @@ function doWatch(
     scheduler = () => queuePostRenderEffect(job, instance && instance.suspense)
   } else {
     // default: 'pre'
-    scheduler = () => queuePreFlushCb(job)
+    job.pre = true
+    if (instance) job.id = instance.uid
+    scheduler = () => queueJob(job)
   }
 
   const effect = new ReactiveEffect(getter, scheduler)

+ 1 - 0
packages/runtime-core/src/component.ts

@@ -814,6 +814,7 @@ export function finishComponentSetup(
           // pass runtime compat config into the compiler
           finalCompilerOptions.compatConfig = Object.create(globalCompatConfig)
           if (Component.compatConfig) {
+            // @ts-expect-error types are not compatible
             extend(finalCompilerOptions.compatConfig, Component.compatConfig)
           }
         }

+ 2 - 1
packages/runtime-core/src/renderer.ts

@@ -1590,7 +1590,7 @@ function baseCreateRenderer(
     pauseTracking()
     // props update may have triggered pre-flush watchers.
     // flush them before the render update.
-    flushPreFlushCbs(undefined, instance.update)
+    flushPreFlushCbs()
     resetTracking()
   }
 
@@ -2331,6 +2331,7 @@ function baseCreateRenderer(
     } else {
       patch(container._vnode || null, vnode, container, null, null, null, isSVG)
     }
+    flushPreFlushCbs()
     flushPostFlushCbs()
     container._vnode = vnode
   }

+ 36 - 66
packages/runtime-core/src/scheduler.ts

@@ -5,6 +5,7 @@ import { warn } from './warning'
 
 export interface SchedulerJob extends Function {
   id?: number
+  pre?: boolean
   active?: boolean
   computed?: boolean
   /**
@@ -39,10 +40,6 @@ let isFlushPending = false
 const queue: SchedulerJob[] = []
 let flushIndex = 0
 
-const pendingPreFlushCbs: SchedulerJob[] = []
-let activePreFlushCbs: SchedulerJob[] | null = null
-let preFlushIndex = 0
-
 const pendingPostFlushCbs: SchedulerJob[] = []
 let activePostFlushCbs: SchedulerJob[] | null = null
 let postFlushIndex = 0
@@ -50,8 +47,6 @@ let postFlushIndex = 0
 const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise<any>
 let currentFlushPromise: Promise<void> | null = null
 
-let currentPreFlushParentJob: SchedulerJob | null = null
-
 const RECURSION_LIMIT = 100
 type CountMap = Map<SchedulerJob, number>
 
@@ -89,12 +84,11 @@ export function queueJob(job: SchedulerJob) {
   // allow it recursively trigger itself - it is the user's responsibility to
   // ensure it doesn't end up in an infinite loop.
   if (
-    (!queue.length ||
-      !queue.includes(
-        job,
-        isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex
-      )) &&
-    job !== currentPreFlushParentJob
+    !queue.length ||
+    !queue.includes(
+      job,
+      isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex
+    )
   ) {
     if (job.id == null) {
       queue.push(job)
@@ -119,71 +113,44 @@ export function invalidateJob(job: SchedulerJob) {
   }
 }
 
-function queueCb(
-  cb: SchedulerJobs,
-  activeQueue: SchedulerJob[] | null,
-  pendingQueue: SchedulerJob[],
-  index: number
-) {
+export function queuePostFlushCb(cb: SchedulerJobs) {
   if (!isArray(cb)) {
     if (
-      !activeQueue ||
-      !activeQueue.includes(cb, cb.allowRecurse ? index + 1 : index)
+      !activePostFlushCbs ||
+      !activePostFlushCbs.includes(
+        cb,
+        cb.allowRecurse ? postFlushIndex + 1 : postFlushIndex
+      )
     ) {
-      pendingQueue.push(cb)
+      pendingPostFlushCbs.push(cb)
     }
   } else {
     // if cb is an array, it is a component lifecycle hook which can only be
     // triggered by a job, which is already deduped in the main queue, so
     // we can skip duplicate check here to improve perf
-    pendingQueue.push(...cb)
+    pendingPostFlushCbs.push(...cb)
   }
   queueFlush()
 }
 
-export function queuePreFlushCb(cb: SchedulerJob) {
-  queueCb(cb, activePreFlushCbs, pendingPreFlushCbs, preFlushIndex)
-}
-
-export function queuePostFlushCb(cb: SchedulerJobs) {
-  queueCb(cb, activePostFlushCbs, pendingPostFlushCbs, postFlushIndex)
-}
-
-export function flushPreFlushCbs(
-  seen?: CountMap,
-  parentJob: SchedulerJob | null = null
-) {
-  if (pendingPreFlushCbs.length) {
-    currentPreFlushParentJob = parentJob
-    activePreFlushCbs = [...new Set(pendingPreFlushCbs)]
-    pendingPreFlushCbs.length = 0
-    if (__DEV__) {
-      seen = seen || new Map()
-    }
-    for (
-      preFlushIndex = 0;
-      preFlushIndex < activePreFlushCbs.length;
-      preFlushIndex++
-    ) {
-      if (
-        __DEV__ &&
-        checkRecursiveUpdates(seen!, activePreFlushCbs[preFlushIndex])
-      ) {
+export function flushPreFlushCbs(seen?: CountMap, i = flushIndex) {
+  if (__DEV__) {
+    seen = seen || new Map()
+  }
+  for (; i < queue.length; i++) {
+    const cb = queue[i]
+    if (cb && cb.pre) {
+      if (__DEV__ && checkRecursiveUpdates(seen!, cb)) {
         continue
       }
-      activePreFlushCbs[preFlushIndex]()
+      queue.splice(i, 1)
+      i--
+      cb()
     }
-    activePreFlushCbs = null
-    preFlushIndex = 0
-    currentPreFlushParentJob = null
-    // recursively flush until it drains
-    flushPreFlushCbs(seen, parentJob)
   }
 }
 
 export function flushPostFlushCbs(seen?: CountMap) {
-  // flush any pre cbs queued during the flush (e.g. pre watchers)
-  flushPreFlushCbs()
   if (pendingPostFlushCbs.length) {
     const deduped = [...new Set(pendingPostFlushCbs)]
     pendingPostFlushCbs.length = 0
@@ -222,6 +189,15 @@ export function flushPostFlushCbs(seen?: CountMap) {
 const getId = (job: SchedulerJob): number =>
   job.id == null ? Infinity : job.id
 
+const comparator = (a: SchedulerJob, b: SchedulerJob): number => {
+  const diff = getId(a) - getId(b)
+  if (diff === 0) {
+    if (a.pre && !b.pre) return -1
+    if (b.pre && !a.pre) return 1
+  }
+  return diff
+}
+
 function flushJobs(seen?: CountMap) {
   isFlushPending = false
   isFlushing = true
@@ -229,8 +205,6 @@ function flushJobs(seen?: CountMap) {
     seen = seen || new Map()
   }
 
-  flushPreFlushCbs(seen)
-
   // Sort queue before flush.
   // This ensures that:
   // 1. Components are updated from parent to child. (because parent is always
@@ -238,7 +212,7 @@ function flushJobs(seen?: CountMap) {
   //    priority number)
   // 2. If a component is unmounted during a parent component's update,
   //    its update can be skipped.
-  queue.sort((a, b) => getId(a) - getId(b))
+  queue.sort(comparator)
 
   // conditional usage of checkRecursiveUpdate must be determined out of
   // try ... catch block since Rollup by default de-optimizes treeshaking
@@ -270,11 +244,7 @@ function flushJobs(seen?: CountMap) {
     currentFlushPromise = null
     // some postFlushCb queued jobs!
     // keep flushing until it drains.
-    if (
-      queue.length ||
-      pendingPreFlushCbs.length ||
-      pendingPostFlushCbs.length
-    ) {
+    if (queue.length || pendingPostFlushCbs.length) {
       flushJobs(seen)
     }
   }

+ 7 - 9
packages/server-renderer/__tests__/render.spec.ts

@@ -128,14 +128,14 @@ function testRender(type: string, render: typeof renderToString) {
           await render(
             createApp(
               defineComponent({
-                extends: {
+                extends: defineComponent({
                   data() {
                     return { msg: 'hello' }
                   },
-                  render(this: any) {
+                  render() {
                     return h('div', this.msg)
                   }
-                }
+                })
               })
             )
           )
@@ -148,14 +148,14 @@ function testRender(type: string, render: typeof renderToString) {
             createApp(
               defineComponent({
                 mixins: [
-                  {
+                  defineComponent({
                     data() {
                       return { msg: 'hello' }
                     },
-                    render(this: any) {
+                    render() {
                       return h('div', this.msg)
                     }
-                  }
+                  })
                 ]
               })
             )
@@ -675,9 +675,7 @@ function testRender(type: string, render: typeof renderToString) {
         const MyComp = {
           render: () => h('p', 'hello')
         }
-        expect(await render(h(KeepAlive, () => h(MyComp)))).toBe(
-          `<p>hello</p>`
-        )
+        expect(await render(h(KeepAlive, () => h(MyComp)))).toBe(`<p>hello</p>`)
       })
 
       test('Transition', async () => {

+ 1 - 1
packages/server-renderer/src/renderToString.ts

@@ -77,7 +77,7 @@ export async function resolveTeleports(context: SSRContext) {
       // note: it's OK to await sequentially here because the Promises were
       // created eagerly in parallel.
       context.teleports[key] = await unrollBuffer(
-        (await Promise.all(context.__teleportBuffers[key])) as SSRBuffer
+        await Promise.all([context.__teleportBuffers[key]])
       )
     }
   }

+ 4 - 2
packages/vue/package.json

@@ -28,11 +28,13 @@
     },
     "./server-renderer": {
       "import": "./server-renderer/index.mjs",
-      "require": "./server-renderer/index.js"
+      "require": "./server-renderer/index.js",
+      "types": "./server-renderer/index.d.ts"
     },
     "./compiler-sfc": {
       "import": "./compiler-sfc/index.mjs",
-      "require": "./compiler-sfc/index.js"
+      "require": "./compiler-sfc/index.js",
+      "types": "./compiler-sfc/index.d.ts"
     },
     "./dist/*": "./dist/*",
     "./package.json": "./package.json",

+ 38 - 36
pnpm-lock.yaml

@@ -48,7 +48,7 @@ importers:
       todomvc-app-css: ^2.3.0
       ts-jest: ^27.0.5
       tslib: ^2.4.0
-      typescript: ^4.6.4
+      typescript: ^4.7.4
       vite: ^2.9.8
       vue: workspace:*
       yorkie: ^2.0.0
@@ -64,7 +64,7 @@ importers:
       '@types/jest': 27.0.3
       '@types/node': 16.11.12
       '@types/puppeteer': 5.4.4
-      '@typescript-eslint/parser': 5.23.0_e4zyhrvfnqudwdx5bevnvkluy4
+      '@typescript-eslint/parser': 5.23.0_hxadhbs2xogijvk7vq4t2azzbu
       '@vue/reactivity': link:packages/reactivity
       '@vue/runtime-core': link:packages/runtime-core
       '@vue/runtime-dom': link:packages/runtime-dom
@@ -75,7 +75,7 @@ importers:
       enquirer: 2.3.6
       esbuild: 0.14.35
       eslint: 7.32.0
-      eslint-plugin-jest: 26.1.5_kkaclaimgki2r45yqzc3bxhmwy
+      eslint-plugin-jest: 26.1.5_fublp7hbjjjut4jarqgrlzb3ey
       execa: 4.1.0
       fs-extra: 9.1.0
       jest: 27.4.4
@@ -91,13 +91,13 @@ importers:
       rollup-plugin-node-globals: 1.4.0
       rollup-plugin-polyfill-node: 0.6.2_rollup@2.38.5
       rollup-plugin-terser: 7.0.2_rollup@2.38.5
-      rollup-plugin-typescript2: 0.27.3_zlmz7jga2mttuvx4qwelsmvyxm
+      rollup-plugin-typescript2: 0.27.3_svygma56heasd5pd4q5yjh2bo4
       semver: 7.3.5
       serve: 12.0.1
       todomvc-app-css: 2.4.1
-      ts-jest: 27.1.1_fl6hqye43ip7rnu7q76f35ejrm
+      ts-jest: 27.1.1_3hnzclobtp5be2lqcsbwijsi7u
       tslib: 2.4.0
-      typescript: 4.6.4
+      typescript: 4.7.4
       vite: 2.9.8
       vue: link:packages/vue
       yorkie: 2.0.0
@@ -912,7 +912,7 @@ packages:
       resolve: 1.17.0
       semver: 7.3.5
       source-map: 0.6.1
-      typescript: 4.5.3
+      typescript: 4.5.5
     dev: true
 
   /@microsoft/tsdoc-config/0.15.2:
@@ -1205,15 +1205,15 @@ packages:
       '@types/yargs-parser': 20.2.1
     dev: true
 
-  /@types/yauzl/2.9.2:
-    resolution: {integrity: sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==}
+  /@types/yauzl/2.10.0:
+    resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
     requiresBuild: true
     dependencies:
       '@types/node': 16.11.12
     dev: true
     optional: true
 
-  /@typescript-eslint/parser/5.23.0_e4zyhrvfnqudwdx5bevnvkluy4:
+  /@typescript-eslint/parser/5.23.0_hxadhbs2xogijvk7vq4t2azzbu:
     resolution: {integrity: sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1225,10 +1225,10 @@ packages:
     dependencies:
       '@typescript-eslint/scope-manager': 5.23.0
       '@typescript-eslint/types': 5.23.0
-      '@typescript-eslint/typescript-estree': 5.23.0_typescript@4.6.4
+      '@typescript-eslint/typescript-estree': 5.23.0_typescript@4.7.4
       debug: 4.3.3
       eslint: 7.32.0
-      typescript: 4.6.4
+      typescript: 4.7.4
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -1259,7 +1259,7 @@ packages:
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
-  /@typescript-eslint/typescript-estree/5.19.0_typescript@4.6.4:
+  /@typescript-eslint/typescript-estree/5.19.0_typescript@4.7.4:
     resolution: {integrity: sha512-dRPuD4ocXdaE1BM/dNR21elSEUPKaWgowCA0bqJ6YbYkvtrPVEvZ+zqcX5a8ECYn3q5iBSSUcBBD42ubaOp0Hw==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1274,13 +1274,13 @@ packages:
       globby: 11.0.4
       is-glob: 4.0.3
       semver: 7.3.5
-      tsutils: 3.21.0_typescript@4.6.4
-      typescript: 4.6.4
+      tsutils: 3.21.0_typescript@4.7.4
+      typescript: 4.7.4
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/typescript-estree/5.23.0_typescript@4.6.4:
+  /@typescript-eslint/typescript-estree/5.23.0_typescript@4.7.4:
     resolution: {integrity: sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1295,13 +1295,13 @@ packages:
       globby: 11.0.4
       is-glob: 4.0.3
       semver: 7.3.5
-      tsutils: 3.21.0_typescript@4.6.4
-      typescript: 4.6.4
+      tsutils: 3.21.0_typescript@4.7.4
+      typescript: 4.7.4
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/utils/5.19.0_e4zyhrvfnqudwdx5bevnvkluy4:
+  /@typescript-eslint/utils/5.19.0_hxadhbs2xogijvk7vq4t2azzbu:
     resolution: {integrity: sha512-ZuEckdupXpXamKvFz/Ql8YnePh2ZWcwz7APICzJL985Rp5C2AYcHO62oJzIqNhAMtMK6XvrlBTZeNG8n7gS3lQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1310,7 +1310,7 @@ packages:
       '@types/json-schema': 7.0.11
       '@typescript-eslint/scope-manager': 5.19.0
       '@typescript-eslint/types': 5.19.0
-      '@typescript-eslint/typescript-estree': 5.19.0_typescript@4.6.4
+      '@typescript-eslint/typescript-estree': 5.19.0_typescript@4.7.4
       eslint: 7.32.0
       eslint-scope: 5.1.1
       eslint-utils: 3.0.0_eslint@7.32.0
@@ -2906,7 +2906,7 @@ packages:
       source-map: 0.6.1
     dev: true
 
-  /eslint-plugin-jest/26.1.5_kkaclaimgki2r45yqzc3bxhmwy:
+  /eslint-plugin-jest/26.1.5_fublp7hbjjjut4jarqgrlzb3ey:
     resolution: {integrity: sha512-su89aDuljL9bTjEufTXmKUMSFe2kZUL9bi7+woq+C2ukHZordhtfPm4Vg+tdioHBaKf8v3/FXW9uV0ksqhYGFw==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -2919,7 +2919,7 @@ packages:
       jest:
         optional: true
     dependencies:
-      '@typescript-eslint/utils': 5.19.0_e4zyhrvfnqudwdx5bevnvkluy4
+      '@typescript-eslint/utils': 5.19.0_hxadhbs2xogijvk7vq4t2azzbu
       eslint: 7.32.0
       jest: 27.4.4
     transitivePeerDependencies:
@@ -3177,7 +3177,7 @@ packages:
       get-stream: 5.2.0
       yauzl: 2.10.0
     optionalDependencies:
-      '@types/yauzl': 2.9.2
+      '@types/yauzl': 2.10.0
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -3521,7 +3521,7 @@ packages:
       source-map: 0.6.1
       wordwrap: 1.0.0
     optionalDependencies:
-      uglify-js: 3.14.4
+      uglify-js: 3.16.1
     dev: true
 
   /hard-rejection/2.1.0:
@@ -5130,6 +5130,7 @@ packages:
     resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
+    dev: false
 
   /nanoid/3.3.4:
     resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
@@ -5597,6 +5598,7 @@ packages:
       nanoid: 3.1.30
       picocolors: 1.0.0
       source-map-js: 1.0.1
+    dev: false
 
   /prelude-ls/1.1.2:
     resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=}
@@ -6118,7 +6120,7 @@ packages:
       terser: 5.10.0
     dev: true
 
-  /rollup-plugin-typescript2/0.27.3_zlmz7jga2mttuvx4qwelsmvyxm:
+  /rollup-plugin-typescript2/0.27.3_svygma56heasd5pd4q5yjh2bo4:
     resolution: {integrity: sha512-gmYPIFmALj9D3Ga1ZbTZAKTXq1JKlTQBtj299DXhqYz9cL3g/AQfUvbb2UhH+Nf++cCq941W2Mv7UcrcgLzJJg==}
     peerDependencies:
       rollup: '>=1.26.3'
@@ -6130,7 +6132,7 @@ packages:
       resolve: 1.17.0
       rollup: 2.38.5
       tslib: 2.0.1
-      typescript: 4.6.4
+      typescript: 4.7.4
     dev: true
 
   /rollup-pluginutils/2.8.2:
@@ -6755,7 +6757,7 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
-  /ts-jest/27.1.1_fl6hqye43ip7rnu7q76f35ejrm:
+  /ts-jest/27.1.1_3hnzclobtp5be2lqcsbwijsi7u:
     resolution: {integrity: sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==}
     engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
     hasBin: true
@@ -6786,7 +6788,7 @@ packages:
       lodash.memoize: 4.1.2
       make-error: 1.3.6
       semver: 7.3.5
-      typescript: 4.6.4
+      typescript: 4.7.4
       yargs-parser: 20.2.9
     dev: true
 
@@ -6806,14 +6808,14 @@ packages:
     resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
     dev: true
 
-  /tsutils/3.21.0_typescript@4.6.4:
+  /tsutils/3.21.0_typescript@4.7.4:
     resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
     engines: {node: '>= 6'}
     peerDependencies:
       typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
     dependencies:
       tslib: 1.14.1
-      typescript: 4.6.4
+      typescript: 4.7.4
     dev: true
 
   /type-check/0.3.2:
@@ -6874,20 +6876,20 @@ packages:
     resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=}
     dev: true
 
-  /typescript/4.5.3:
-    resolution: {integrity: sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==}
+  /typescript/4.5.5:
+    resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==}
     engines: {node: '>=4.2.0'}
     hasBin: true
     dev: true
 
-  /typescript/4.6.4:
-    resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==}
+  /typescript/4.7.4:
+    resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
     engines: {node: '>=4.2.0'}
     hasBin: true
     dev: true
 
-  /uglify-js/3.14.4:
-    resolution: {integrity: sha512-AbiSR44J0GoCeV81+oxcy/jDOElO2Bx3d0MfQCUShq7JRXaM4KtQopZsq2vFv8bCq2yMaGrw1FgygUd03RyRDA==}
+  /uglify-js/3.16.1:
+    resolution: {integrity: sha512-X5BGTIDH8U6IQ1TIRP62YC36k+ULAa1d59BxlWvPUJ1NkW5L3FwcGfEzuVvGmhJFBu0YJ5Ge25tmRISqCmLiRQ==}
     engines: {node: '>=0.8.0'}
     hasBin: true
     requiresBuild: true

+ 32 - 1
test-dts/defineComponent.test-d.tsx

@@ -1163,6 +1163,38 @@ describe('should allow to assign props', () => {
   expectType<JSX.Element>(<Parent {...child.$props} />)
 })
 
+// #6052
+describe('prop starting with `on*` is broken', () => {
+  defineComponent({
+    props: {
+      onX: {
+        type: Function as PropType<(a: 1) => void>,
+        required: true
+      }
+    },
+    setup(props) {
+      expectType<(a: 1) => void>(props.onX)
+      props.onX(1)
+    }
+  })
+
+  defineComponent({
+    props: {
+      onX: {
+        type: Function as PropType<(a: 1) => void>,
+        required: true
+      }
+    },
+    emits: {
+      test: (a: 1) => true
+    },
+    setup(props) {
+      expectType<(a: 1) => void>(props.onX)
+      expectType<undefined | ((a: 1) => any)>(props.onTest)
+    }
+  })
+})
+
 // check if defineComponent can be exported
 export default {
   // function components
@@ -1209,5 +1241,4 @@ declare const MyButton: DefineComponent<
   Readonly<ExtractPropTypes<{}>>,
   {}
 >
-
 ;<MyButton class="x" />