Browse Source

fix(types): keep the original type when unwrapping `markRaw` (#3791)

Carlos Rodrigues 4 năm trước cách đây
mục cha
commit
32e53bfd47

+ 4 - 2
packages/reactivity/src/reactive.ts

@@ -11,7 +11,7 @@ import {
   shallowCollectionHandlers,
   shallowReadonlyCollectionHandlers
 } from './collectionHandlers'
-import { UnwrapRefSimple, Ref } from './ref'
+import { UnwrapRefSimple, Ref, RawSymbol } from './ref'
 
 export const enum ReactiveFlags {
   SKIP = '__v_skip',
@@ -241,7 +241,9 @@ export function toRaw<T>(observed: T): T {
   return raw ? toRaw(raw) : observed
 }
 
-export function markRaw<T extends object>(value: T): T {
+export function markRaw<T extends object>(
+  value: T
+): T & { [RawSymbol]?: true } {
   def(value, ReactiveFlags.SKIP, true)
   return value
 }

+ 2 - 0
packages/reactivity/src/ref.ts

@@ -12,6 +12,7 @@ import { CollectionTypes } from './collectionHandlers'
 import { createDep, Dep } from './dep'
 
 declare const RefSymbol: unique symbol
+export declare const RawSymbol: unique symbol
 
 export interface Ref<T = any> {
   value: T
@@ -291,6 +292,7 @@ export type UnwrapRefSimple<T> = T extends
   | BaseTypes
   | Ref
   | RefUnwrapBailTypes[keyof RefUnwrapBailTypes]
+  | { [RawSymbol]?: true }
   ? T
   : T extends Array<any>
   ? { [K in keyof T]: UnwrapRefSimple<T[K]> }

+ 3 - 3
test-dts/index.d.ts

@@ -9,9 +9,9 @@ export function expectType<T>(value: T): void
 export function expectError<T>(value: T): void
 export function expectAssignable<T, T2 extends T = T>(value: T2): void
 
-export type IsUnion<T, U extends T = T> = (T extends any
-  ? (U extends T ? false : true)
-  : never) extends false
+export type IsUnion<T, U extends T = T> = (
+  T extends any ? (U extends T ? false : true) : never
+) extends false
   ? false
   : true
 

+ 40 - 2
test-dts/reactivity.test-d.ts

@@ -1,5 +1,14 @@
-import { shallowReadonly } from '@vue/reactivity'
-import { ref, readonly, describe, expectError, expectType, Ref } from './index'
+import {
+  ref,
+  readonly,
+  shallowReadonly,
+  describe,
+  expectError,
+  expectType,
+  Ref,
+  reactive,
+  markRaw
+} from './index'
 
 describe('should support DeepReadonly', () => {
   const r = readonly({ obj: { k: 'v' } })
@@ -15,6 +24,35 @@ describe('readonly ref', () => {
   expectType<Ref>(r)
 })
 
+describe('should support markRaw', () => {
+  class Test<T> {
+    item = {} as Ref<T>
+  }
+  const test = new Test<number>()
+  const plain = {
+    ref: ref(1)
+  }
+
+  const r = reactive({
+    class: {
+      raw: markRaw(test),
+      reactive: test
+    },
+    plain: {
+      raw: markRaw(plain),
+      reactive: plain
+    }
+  })
+
+  expectType<Test<number>>(r.class.raw)
+  // @ts-expect-error it should unwrap
+  expectType<Test<number>>(r.class.reactive)
+
+  expectType<Ref<number>>(r.plain.raw.ref)
+  // @ts-expect-error it should unwrap
+  expectType<Ref<number>>(r.plain.reactive.ref)
+})
+
 describe('shallowReadonly ref unwrap', () => {
   const r = shallowReadonly({ count: { n: ref(1) } })
   // @ts-expect-error