diff --git a/packages-private/dts-test/defineComponent.test-d.tsx b/packages-private/dts-test/defineComponent.test-d.tsx index fda3ca485..422897314 100644 --- a/packages-private/dts-test/defineComponent.test-d.tsx +++ b/packages-private/dts-test/defineComponent.test-d.tsx @@ -11,6 +11,7 @@ import { defineComponent, h, reactive, + readonly, ref, withKeys, withModifiers, @@ -190,6 +191,7 @@ describe('with object props', () => { f: reactive({ g: ref('hello' as GT), }), + m: readonly(ref(1)), } }, provide() { @@ -259,6 +261,9 @@ describe('with object props', () => { // setup context properties should be mutable this.c = 2 + // @ts-expect-error setup context readonly properties should not be mutable + this.m = 2 + return null }, }) diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 59b713dd8..524311d69 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -1,5 +1,6 @@ import { type IfAny, + type IfEquals, hasChanged, isArray, isFunction, @@ -486,9 +487,20 @@ function propertyToRef( export interface RefUnwrapBailTypes {} export type ShallowUnwrapRef = { - [K in keyof T]: DistributeRef + [K in keyof Pick>]: DistributeRef +} & { + readonly [K in keyof Omit>]: DistributeRef } +type MutableKeys = { + [K in keyof T]-?: IfEquals< + { [P in keyof T[K]]: T[K][P] }, + { -readonly [P in keyof T[K]]: T[K][P] }, + K, + never + > +}[keyof T] + type DistributeRef = T extends Ref ? V : T export type UnwrapRef = diff --git a/packages/shared/src/typeUtils.ts b/packages/shared/src/typeUtils.ts index f5b9e6ec3..ec8531e46 100644 --- a/packages/shared/src/typeUtils.ts +++ b/packages/shared/src/typeUtils.ts @@ -13,6 +13,10 @@ export type LooseRequired = { [P in keyof (T & Required)]: T[P] } // https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360 export type IfAny = 0 extends 1 & T ? Y : N +// https://stackoverflow.com/questions/52443276/how-to-exclude-getter-only-properties-from-type-in-typescript/52473108#52473108 +export type IfEquals = + (() => T extends A ? 1 : 2) extends () => T extends B ? 1 : 2 ? Y : N + export type IsKeyValues = IfAny< T, false,