diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap
index 32acabe3d..dbe6aa1dd 100644
--- a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap
@@ -33,8 +33,8 @@ return { a, b, c }
}"
`;
-exports[``)
- expect(content).toMatch(`import { ref as _ref } from 'vue'`)
+ expect(content).toMatch(
+ `import { ref as _ref, shallowRef as _shallowRef } from 'vue'`
+ )
expect(content).not.toMatch(`$ref()`)
expect(content).not.toMatch(`$ref(1)`)
- expect(content).not.toMatch(`$ref({`)
+ expect(content).not.toMatch(`$shallowRef({`)
expect(content).toMatch(`let foo = _ref()`)
expect(content).toMatch(`let a = _ref(1)`)
expect(content).toMatch(`
- let b = _ref({
+ let b = _shallowRef({
count: 0
})
`)
diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts
index 000dff412..9e4a2ceb8 100644
--- a/packages/compiler-sfc/src/compileScript.ts
+++ b/packages/compiler-sfc/src/compileScript.ts
@@ -65,6 +65,7 @@ const DEFINE_EXPOSE = 'defineExpose'
const WITH_DEFAULTS = 'withDefaults'
const $REF = `$ref`
+const $SHALLOW_REF = '$shallowRef'
const $COMPUTED = `$computed`
const $FROM_REFS = `$fromRefs`
const $RAW = `$raw`
@@ -531,7 +532,12 @@ export function compileScript(
}
function isRefSugarCall(callee: string) {
- return callee === $REF || callee === $COMPUTED || callee === $FROM_REFS
+ return (
+ callee === $REF ||
+ callee === $COMPUTED ||
+ callee === $FROM_REFS ||
+ callee === $SHALLOW_REF
+ )
}
function processRefSugar(
@@ -558,24 +564,28 @@ export function compileScript(
const callee = (decl.init.callee as Identifier).name
const start = decl.init.start! + startOffset
- if (callee === $REF) {
+ if (callee === $REF || callee === $SHALLOW_REF) {
if (statement.kind !== 'let') {
- error(`${$REF}() bindings can only be declared with let.`, decl)
+ error(`${callee}() bindings can only be declared with let.`, decl)
}
if (decl.id.type !== 'Identifier') {
error(
- `${$REF}() bindings cannot be used with destructuring. ` +
+ `${callee}() bindings cannot be used with destructuring. ` +
`If you are trying to destructure from an object of refs, ` +
`use \`let { x } = $fromRefs(obj)\`.`,
decl.id
)
}
registerRefBinding(decl.id)
- s.overwrite(start, start + $REF.length, helper('ref'))
+ s.overwrite(
+ start,
+ start + callee.length,
+ helper(callee === $REF ? 'ref' : 'shallowRef')
+ )
} else if (callee === $COMPUTED) {
if (decl.id.type !== 'Identifier') {
error(
- `${$COMPUTED}() bindings cannot be used with destructuring.`,
+ `${callee}() bindings cannot be used with destructuring.`,
decl.id
)
}
@@ -584,7 +594,7 @@ export function compileScript(
} else if (callee === $FROM_REFS) {
if (!decl.id.type.endsWith('Pattern')) {
error(
- `${$FROM_REFS}() declaration must be used with destructure patterns.`,
+ `${callee}() declaration must be used with destructure patterns.`,
decl
)
}
@@ -1124,10 +1134,7 @@ export function compileScript(
return false // skip walk
} else if (
parent &&
- isCallOf(
- node,
- id => id === $REF || id === $FROM_REFS || id === $COMPUTED
- ) &&
+ isCallOf(node, isRefSugarCall) &&
(parent.type !== 'VariableDeclarator' || node !== parent.init)
) {
error(
diff --git a/packages/runtime-core/src/helpers/refSugar.ts b/packages/runtime-core/src/helpers/refSugar.ts
index 4c62441d2..91480dfa9 100644
--- a/packages/runtime-core/src/helpers/refSugar.ts
+++ b/packages/runtime-core/src/helpers/refSugar.ts
@@ -3,6 +3,10 @@ import { Ref, UnwrapRef, ShallowUnwrapRef, ComputedRef } from '@vue/reactivity'
export function $ref(arg: T | Ref): UnwrapRef
export function $ref() {}
+export function $shallowRef(arg: T): T {
+ return arg
+}
+
declare const ComputedRefMarker: unique symbol
type ComputedRefValue = T & { [ComputedRefMarker]?: any }
diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts
index a784bd73f..c46b6df22 100644
--- a/packages/runtime-core/src/index.ts
+++ b/packages/runtime-core/src/index.ts
@@ -354,4 +354,10 @@ export const compatUtils = (
// Ref sugar macros ------------------------------------------------------------
// for dts generation only
-export { $ref, $computed, $raw, $fromRefs } from './helpers/refSugar'
+export {
+ $ref,
+ $shallowRef,
+ $computed,
+ $raw,
+ $fromRefs
+} from './helpers/refSugar'
diff --git a/packages/runtime-core/types/scriptSetupHelpers.d.ts b/packages/runtime-core/types/scriptSetupHelpers.d.ts
index fc56cb19c..69cab07ad 100644
--- a/packages/runtime-core/types/scriptSetupHelpers.d.ts
+++ b/packages/runtime-core/types/scriptSetupHelpers.d.ts
@@ -6,6 +6,7 @@ type _defineExpose = typeof defineExpose
type _withDefaults = typeof withDefaults
type _ref = typeof $ref
+type _shallowRef = typeof $shallowRef
type _computed = typeof $computed
type _fromRefs = typeof $fromRefs
type _raw = typeof $raw
@@ -17,6 +18,7 @@ declare global {
const withDefaults: _withDefaults
const $ref: _ref
+ const $shallowRef: _shallowRef
const $computed: _computed
const $fromRefs: _fromRefs
const $raw: _raw
diff --git a/test-dts/refSugar.test-d.ts b/test-dts/refSugar.test-d.ts
index 29d837091..4ea579b91 100644
--- a/test-dts/refSugar.test-d.ts
+++ b/test-dts/refSugar.test-d.ts
@@ -1,6 +1,7 @@
import {
expectType,
$ref,
+ $shallowRef,
$computed,
$fromRefs,
$raw,
@@ -14,6 +15,10 @@ expectType($ref(1))
expectType($ref(ref(1)))
expectType<{ foo: number }>($ref({ foo: ref(1) }))
+// $shallowRef
+expectType($shallowRef(1))
+expectType<{ foo: Ref }>($shallowRef({ foo: ref(1) }))
+
// $computed
expectType($computed(() => 1))
let b = $ref(1)