Repository: vuejs/vue
Pull request: fix#12978 shallowRef's return type 

close #12978

**What kind of change does this PR introduce?** (check at least one)

- [X] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [X] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [X] It's submitted to the `main` branch for v2.x (or to a previous version branch)
- [X] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [X] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [X] New/updated tests are included

**Other information:**

See #12978 

Changed files:
filename: src/v3/reactivity/ref.ts
patch: @@ -40,9 +40,7 @@ export function isRef(r: any): r is Ref {
   return !!(r && (r as Ref).__v_isRef === true)
 }
 
-export function ref<T extends object>(
-  value: T
-): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>
+export function ref<T extends Ref>(value: T): T
 export function ref<T>(value: T): Ref<UnwrapRef<T>>
 export function ref<T = any>(): Ref<T | undefined>
 export function ref(value?: unknown) {
@@ -53,9 +51,8 @@ declare const ShallowRefMarker: unique symbol
 
 export type ShallowRef<T = any> = Ref<T> & { [ShallowRefMarker]?: true }
 
-export function shallowRef<T extends object>(
-  value: T
-): T extends Ref ? T : ShallowRef<T>
+export function shallowRef<T>(value: T | Ref<T>): Ref<T> | ShallowRef<T>
+export function shallowRef<T extends Ref>(value: T): T
 export function shallowRef<T>(value: T): ShallowRef<T>
 export function shallowRef<T = any>(): ShallowRef<T | undefined>
 export function shallowRef(value?: unknown) {

filename: types/test/v3/reactivity-test.ts
patch: @@ -15,7 +15,7 @@ import {
   set,
   del
 } from '../../index'
-import { describe, expectType } from '../utils'
+import { IsUnion, describe, expectType } from '../utils'
 
 function plainType(arg: number | Ref<number>) {
   // ref coercing
@@ -385,3 +385,14 @@ describe('set/del', () => {
   // @ts-expect-error
   del([], 'fse', 123)
 })
+
+
+{
+  //#12978
+  type Steps = { step: '1' } | { step: '2' }
+  const shallowUnionGenParam = shallowRef<Steps>({ step: '1' })
+  const shallowUnionAsCast = shallowRef({ step: '1' } as Steps)
+
+  expectType<IsUnion<typeof shallowUnionGenParam>>(false)
+  expectType<IsUnion<typeof shallowUnionAsCast>>(false)
+}
\ No newline at end of file

filename: types/test/v3/watch-test.ts
patch: @@ -1,4 +1,4 @@
-import { ref, computed, watch } from '../../index'
+import { ref, computed, watch, shallowRef } from '../../index'
 import { expectType } from '../utils'
 
 const source = ref('foo')
@@ -76,3 +76,17 @@ watch([someRef, otherRef], values => {
   // no type error
   console.log(value2.a)
 })
+
+{
+  //#12978
+  type Steps = { step: '1' } | { step: '2' }
+  const shallowUnionGenParam = shallowRef<Steps>({ step: '1' })
+  const shallowUnionAsCast = shallowRef({ step: '1' } as Steps)
+
+  watch(shallowUnionGenParam, value => {
+    expectType<Steps>(value)
+  })
+  watch(shallowUnionAsCast, value => {
+    expectType<Steps>(value)
+  })
+}
\ No newline at end of file