From 815bfcffae7a9f04ee996367a731e6e072af6bd2 Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 4 Sep 2021 16:42:39 -0400 Subject: [PATCH] fix(types): fix ref macro types fix #4499 --- packages/reactivity/src/computed.ts | 3 ++ packages/reactivity/src/ref.ts | 3 +- packages/vue/ref-macros.d.ts | 52 ++++++++++++++------ test-dts/refTransformMacros.test-d.ts | 69 ++++++++++++++++++++++----- 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index 3b3734388a1..b3292588435 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -4,8 +4,11 @@ import { isFunction, NOOP } from '@vue/shared' import { ReactiveFlags, toRaw } from './reactive' import { Dep } from './dep' +declare const ComoutedRefSymbol: unique symbol + export interface ComputedRef extends WritableComputedRef { readonly value: T + [ComoutedRefSymbol]: true } export interface WritableComputedRef extends Ref { diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 382afaa8016..32426aaf3e5 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -251,7 +251,8 @@ export interface RefUnwrapBailTypes {} export type ShallowUnwrapRef = { [K in keyof T]: T[K] extends Ref ? V - : T[K] extends Ref | undefined // if `V` is `unknown` that means it does not extend `Ref` and is undefined + : // if `V` is `unknown` that means it does not extend `Ref` and is undefined + T[K] extends Ref | undefined ? unknown extends V ? undefined : V | undefined diff --git a/packages/vue/ref-macros.d.ts b/packages/vue/ref-macros.d.ts index ee8ddfed9b9..c38b4bad719 100644 --- a/packages/vue/ref-macros.d.ts +++ b/packages/vue/ref-macros.d.ts @@ -4,18 +4,30 @@ import { ComputedRef, WritableComputedOptions, DebuggerOptions, - WritableComputedRef, - ShallowUnwrapRef + WritableComputedRef } from '@vue/runtime-dom' -declare const RefMarker: unique symbol -type RefValue = T & { [RefMarker]?: any } +declare const RefType: unique symbol -declare const ComputedRefMarker: unique symbol -type ComputedRefValue = T & { [ComputedRefMarker]?: any } +declare const enum RefTypes { + Ref = 1, + ComputedRef = 2, + WritableComputedRef = 3 +} + +type RefValue = T extends null | undefined + ? T + : T & { [RefType]?: RefTypes.Ref } + +type ComputedRefValue = T extends null | undefined + ? T + : T & { [RefType]?: RefTypes.ComputedRef } + +type WritableComputedRefValue = T extends null | undefined + ? T + : T & { [RefType]?: RefTypes.WritableComputedRef } -declare const WritableComputedRefMarker: unique symbol -type WritableComputedRefValue = T & { [WritableComputedRefMarker]?: any } +type NormalObject = T & { [RefType]?: never } /** * Vue ref transform macro for binding refs as reactive variables. @@ -23,25 +35,35 @@ type WritableComputedRefValue = T & { [WritableComputedRefMarker]?: any } declare function _$(arg: ComputedRef): ComputedRefValue declare function _$(arg: WritableComputedRef): WritableComputedRefValue declare function _$(arg: Ref): RefValue -declare function _$(arg?: T): ShallowUnwrapRef +declare function _$(arg?: T): DestructureRefs + +type DestructureRefs = { + [K in keyof T]: T[K] extends ComputedRef + ? ComputedRefValue + : T[K] extends WritableComputedRef + ? WritableComputedRefValue + : T[K] extends Ref + ? RefValue + : T[K] +} /** * Vue ref transform macro for accessing underlying refs of reactive varaibles. */ +declare function _$$(arg: NormalObject): ToRawRefs +declare function _$$(value: RefValue): Ref declare function _$$(value: ComputedRefValue): ComputedRef declare function _$$( value: WritableComputedRefValue ): WritableComputedRef -declare function _$$(value: RefValue): Ref -declare function _$$(arg: T): ToRawRefs type ToRawRefs = { - [K in keyof T]: T[K] extends ComputedRefValue - ? ComputedRefValue + [K in keyof T]: T[K] extends RefValue + ? Ref + : T[K] extends ComputedRefValue + ? ComputedRef : T[K] extends WritableComputedRefValue ? WritableComputedRef - : T[K] extends RefValue - ? Ref : T[K] extends object ? T[K] extends | Function diff --git a/test-dts/refTransformMacros.test-d.ts b/test-dts/refTransformMacros.test-d.ts index dfabb55fb5e..f0abb30424f 100644 --- a/test-dts/refTransformMacros.test-d.ts +++ b/test-dts/refTransformMacros.test-d.ts @@ -1,14 +1,55 @@ import { WritableComputedRef } from '@vue/reactivity' -import { expectType, ref, Ref, ComputedRef } from './index' +import { expectType, ref, computed, Ref, ComputedRef } from './index' import 'vue/ref-macros' +import { RefType, RefTypes } from 'vue/ref-macros' // wrapping refs + // normal +let n = $(ref(1)) +n = 2 +// @ts-expect-error +n = 'foo' + +// #4499 nullable +let msg = $(ref(null)) +msg = 'hello world' +msg = null +expectType(msg![RefType]) + // computed +let m = $(computed(() => n + 1)) +m * 1 +// @ts-expect-error +m.slice() +expectType(m[RefType]) + // writable computed +let wc = $( + computed({ + get: () => n + 1, + set: v => (n = v - 1) + }) +) +wc = 2 +// @ts-expect-error +wc = 'foo' +expectType(wc[RefType]) // destructure -const { x, y, z } = $(useFoo()) +function useFoo() { + let x = $ref(1) + let y = $computed(() => 'hi') + + return $$({ + x, + y, + z: 123 + }) +} + +const fooRes = useFoo() +const { x, y, z } = $(fooRes) expectType(x) expectType(y) expectType(z) @@ -39,17 +80,12 @@ expectType( }) ) -function useFoo() { - return { - x: ref(1), - y: ref('hi'), - z: 123 - } -} - // $$ -expectType>($$(x)) -expectType>($$(y)) +const xRef = $$(x) +expectType>(xRef) + +const yRef = $$(y) +expectType>(yRef) const c = $computed(() => 1) const cRef = $$(c) @@ -63,3 +99,12 @@ const c2Ref = $$(c2) expectType>(c2Ref) // $$ on object +const obj = $$({ + n, + m, + wc +}) + +expectType>(obj.n) +expectType>(obj.m) +expectType>(obj.wc)