Repository: vuejs/vue-next (ts)

Issue:
types: DefineComponent turns `any` props into `unknown`
### Version
3.2.22

### Reproduction link
[sfc.vuejs.org/](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cCBsYW5nPVwidHNcIj5cblx0ZGVmaW5lUHJvcHM8eyB3aGF0ZXZlcjogYW55IH0+KClcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxkaXY+XG4gICAgSWYgVFMgY2hlY2tzIHlvdXIgdGVtcGxhdGUsIGUuZy4gdXNpbmcgVm9sYXIsIHdoYXRldmVyIGlzIHR5cGVkIGFzIHVua25vd24gYW5kIHRoaXMgaXMgYW4gZXJyb3I6XG4gICAge3t3aGF0ZXZlci5zb21lfX1cbiAgPC9kaXY+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)







### Steps to reproduce
Using Typescript, define a props typed as `any`.
Try to access random members in template.

![image](https://user-images.githubusercontent.com/3832820/142831410-9c29454b-11df-49e3-84bd-17115cc5082e.png)


### What is expected?
No compilation error

### What is actually happening?
Typescript complains, because the props is of type `unknown`

---
Downstream issue in Volar: johnsoncodehk/volar#713
@johnsoncodehk traced the issue to be in `defineComponent` typings.

<!-- generated by vue-issues. DO NOT REMOVE -->

Pull request:
fix(types): propType<any> type infer
fix #4983 
from [url](https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360)

Patch:
diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts
index 29367007c..0fa1c4bc2 100644
--- a/packages/reactivity/src/baseHandlers.ts
+++ b/packages/reactivity/src/baseHandlers.ts
@@ -7,7 +7,8 @@ import {
   readonlyMap,
   reactiveMap,
   shallowReactiveMap,
-  shallowReadonlyMap
+  shallowReadonlyMap,
+  isReadonly
 } from './reactive'
 import { TrackOpTypes, TriggerOpTypes } from './operations'
 import {
@@ -146,7 +147,7 @@ function createSetter(shallow = false) {
     receiver: object
   ): boolean {
     let oldValue = (target as any)[key]
-    if (!shallow) {
+    if (!shallow && !isReadonly(value)) {
       value = toRaw(value)
       oldValue = toRaw(oldValue)
       if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts
index fb43668e4..93eb4fa89 100644
--- a/packages/reactivity/src/ref.ts
+++ b/packages/reactivity/src/ref.ts
@@ -190,9 +190,7 @@ export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
 }
 
 export type ToRefs<T = any> = {
-  // #2687: somehow using ToRef<T[K]> here turns the resulting type into
-  // a union of multiple Ref<*> types instead of a single Ref<* | *> type.
-  [K in keyof T]: T[K] extends Ref ? T[K] : Ref<UnwrapRef<T[K]>>
+  [K in keyof T]: ToRef<T[K]>
 }
 export function toRefs<T extends object>(object: T): ToRefs<T> {
   if (__DEV__ && !isProxy(object)) {
diff --git a/packages/runtime-core/src/apiSetupHelpers.ts b/packages/runtime-core/src/apiSetupHelpers.ts
index fc1866af9..02ca5d53e 100644
--- a/packages/runtime-core/src/apiSetupHelpers.ts
+++ b/packages/runtime-core/src/apiSetupHelpers.ts
@@ -131,6 +131,7 @@ type InferDefaults<T> = {
 }
 
 type InferDefault<P, T> = T extends
+  | null
   | number
   | string
   | boolean
diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts
index 924f40a73..c99949222 100644
--- a/packages/runtime-core/src/componentProps.ts
+++ b/packages/runtime-core/src/componentProps.ts
@@ -39,6 +39,7 @@ import { createPropsDefaultThis } from './compat/props'
 import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
 import { DeprecationTypes } from './compat/compatConfig'
 import { shouldSkipAttr } from './compat/attrsFallthrough'
+import { IfAny } from './helpers/typeUtils'
 
 export type ComponentPropsOptions<P = Data> =
   | ComponentObjectPropsOptions<P>
@@ -115,7 +116,7 @@ type InferPropType<T> = [T] extends [null]
     : InferPropType<U>
   : [T] extends [Prop<infer V, infer D>]
   ? unknown extends V
-    ? D
+    ? IfAny<V, V, D>
     : V
   : T
 
diff --git a/packages/runtime-core/src/helpers/typeUtils.ts b/packages/runtime-core/src/helpers/typeUtils.ts
index 204543e6d..8caba54c6 100644
--- a/packages/runtime-core/src/helpers/typeUtils.ts
+++ b/packages/runtime-core/src/helpers/typeUtils.ts
@@ -6,3 +6,5 @@ export type UnionToIntersection<U> = (
 
 // make keys required but keep undefined values
 export type LooseRequired<T> = { [P in string & keyof T]: T[P] }
+
+export type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N


Test patch:
diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts
index 694619174..85b9f9a41 100644
--- a/packages/compiler-sfc/__tests__/compileScript.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts
@@ -292,7 +292,7 @@ defineExpose({ foo: 123 })
       let foo = $ref(1)
       </script>
       `,
-        { refSugar: true }
+        { refTransform: true }
       )
       assertCode(content)
       expect(content).toMatch(`import { ref } from 'vue'`)
@@ -1090,7 +1090,7 @@ const emit = defineEmits(['a', 'b'])
   describe('async/await detection', () => {
     function assertAwaitDetection(code: string, shouldAsync = true) {
       const { content } = compile(`<script setup>${code}</script>`, {
-        refSugar: true
+        refTransform: true
       })
       if (shouldAsync) {
         expect(content).toMatch(`let __temp, __restore`)
diff --git a/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts b/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts
index 34dc9efea..d2f525890 100644
--- a/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts
@@ -5,7 +5,7 @@ import { compileSFCScript as compile, assertCode } from './utils'
 // transform can be found in <root>/packages/ref-transform/__tests__
 describe('sfc ref transform', () => {
   function compileWithRefTransform(src: string) {
-    return compile(src, { refSugar: true })
+    return compile(src, { refTransform: true })
   }
 
   test('$ unwrapping', () => {
@@ -156,7 +156,7 @@ describe('sfc ref transform', () => {
           bar
         })
       </script>`,
-          { refSugar: true }
+          { refTransform: true }
         )
       ).toThrow(`cannot reference locally declared variables`)
 
@@ -168,7 +168,7 @@ describe('sfc ref transform', () => {
           bar
         })
       </script>`,
-          { refSugar: true }
+          { refTransform: true }
         )
       ).toThrow(`cannot reference locally declared variables`)
     })
diff --git a/packages/reactivity/__tests__/readonly.spec.ts b/packages/reactivity/__tests__/readonly.spec.ts
index 63426bb5e..185bb3107 100644
--- a/packages/reactivity/__tests__/readonly.spec.ts
+++ b/packages/reactivity/__tests__/readonly.spec.ts
@@ -465,4 +465,13 @@ describe('reactivity/readonly', () => {
       'Set operation on key "randomProperty" failed: target is readonly.'
     ).toHaveBeenWarned()
   })
+
+  // #4986
+  test('setting a readonly object as a property of a reactive object should retain readonly proxy', () => {
+    const r = readonly({})
+    const rr = reactive({}) as any
+    rr.foo = r
+    expect(rr.foo).toBe(r)
+    expect(isReadonly(rr.foo)).toBe(true)
+  })
 })
diff --git a/test-dts/component.test-d.ts b/test-dts/component.test-d.ts
index 93c3ea410..d8d3934b9 100644
--- a/test-dts/component.test-d.ts
+++ b/test-dts/component.test-d.ts
@@ -10,7 +10,8 @@ import {
   ShallowUnwrapRef,
   FunctionalComponent,
   ComponentPublicInstance,
-  toRefs
+  toRefs,
+  IsAny
 } from './index'
 
 declare function extractComponentOptions<Props, RawBindings>(
@@ -62,6 +63,7 @@ describe('object props', () => {
     ffff: Ref<(a: number, b: string) => { a: boolean }>
     validated: Ref<string | undefined>
     object: Ref<object | undefined>
+    zzz: any
   }
 
   describe('defineComponent', () => {
@@ -130,7 +132,8 @@ describe('object props', () => {
           // validator requires explicit annotation
           validator: (val: unknown) => val !== ''
         },
-        object: Object as PropType<object>
+        object: Object as PropType<object>,
+        zzz: Object as PropType<any>
       },
       setup(props) {
         const refs = toRefs(props)
@@ -152,6 +155,7 @@ describe('object props', () => {
         expectType<ExpectedRefs['ffff']>(refs.ffff)
         expectType<ExpectedRefs['validated']>(refs.validated)
         expectType<ExpectedRefs['object']>(refs.object)
+        expectType<IsAny<typeof props.zzz>>(true)
 
         return {
           setupA: 1,
diff --git a/test-dts/index.d.ts b/test-dts/index.d.ts
index 3d8d288fa..59eadcb92 100644
--- a/test-dts/index.d.ts
+++ b/test-dts/index.d.ts
@@ -14,3 +14,5 @@ export type IsUnion<T, U extends T = T> = (T extends any
   : never) extends false
   ? false
   : true
+
+export type IsAny<T> = 0 extends (1 & T) ? true : false
diff --git a/test-dts/ref.test-d.ts b/test-dts/ref.test-d.ts
index d4462db9e..5b5274c98 100644
--- a/test-dts/ref.test-d.ts
+++ b/test-dts/ref.test-d.ts
@@ -10,8 +10,7 @@ import {
   toRef,
   toRefs,
   ToRefs,
-  shallowReactive,
-  watch
+  shallowReactive
 } from './index'
 
 function plainType(arg: number | Ref<number>) {
@@ -185,28 +184,45 @@ const p2 = proxyRefs(r2)
 expectType<number>(p2.a)
 expectType<Ref<string>>(p2.obj.k)
 
-// toRef
-const obj = {
-  a: 1,
-  b: ref(1)
-}
-expectType<Ref<number>>(toRef(obj, 'a'))
-expectType<Ref<number>>(toRef(obj, 'b'))
+// toRef and toRefs
+{
+  const obj: {
+    a: number
+    b: Ref<number>
+    c: number | string
+  } = {
+    a: 1,
+    b: ref(1),
+    c: 1
+  }
 
-const objWithUnionProp: { a: string | number } = {
-  a: 1
-}
+  // toRef
+  expectType<Ref<number>>(toRef(obj, 'a'))
+  expectType<Ref<number>>(toRef(obj, 'b'))
+  // Should not distribute Refs over union
+  expectType<Ref<number | string>>(toRef(obj, 'c'))
+
+  // toRefs
+  expectType<{
+    a: Ref<number>
+    b: Ref<number>
+    // Should not distribute Refs over union
+    c: Ref<number | string>
+  }>(toRefs(obj))
+
+  // Both should not do any unwrapping
+  const someReactive = shallowReactive({
+    a: {
+      b: ref(42)
+    }
+  })
 
-watch(toRef(objWithUnionProp, 'a'), value => {
-  expectType<string | number>(value)
-})
+  const toRefResult = toRef(someReactive, 'a')
+  const toRefsResult = toRefs(someReactive)
 
-// toRefs
-const objRefs = toRefs(obj)
-expectType<{
-  a: Ref<number>
-  b: Ref<number>
-}>(objRefs)
+  expectType<Ref<number>>(toRefResult.value.b)
+  expectType<Ref<number>>(toRefsResult.a.value.b)
+}
 
 // #2687
 interface AppData {
@@ -238,20 +254,6 @@ function testUnrefGenerics<T>(p: T | Ref<T>) {
 
 testUnrefGenerics(1)
 
-// #4732
-describe('ref in shallow reactive', () => {
-  const baz = shallowReactive({
-    foo: {
-      bar: ref(42)
-    }
-  })
-
-  const foo = toRef(baz, 'foo')
-
-  expectType<Ref<number>>(foo.value.bar)
-  expectType<number>(foo.value.bar.value)
-})
-
 // #4771
 describe('shallow reactive in reactive', () => {
   const baz = reactive({