Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(types): should unwrap tuple correctly (#3820)
fix #3819
  • Loading branch information
hyf0 committed Oct 26, 2022
1 parent 09bb3e9 commit e816812
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 70 deletions.
13 changes: 5 additions & 8 deletions packages/reactivity/src/ref.ts
Expand Up @@ -280,13 +280,10 @@ export interface RefUnwrapBailTypes {}

export type ShallowUnwrapRef<T> = {
[K in keyof T]: T[K] extends Ref<infer V>
? V
: // if `V` is `unknown` that means it does not extend `Ref` and is undefined
T[K] extends Ref<infer V> | undefined
? unknown extends V
? undefined
: V | undefined
: T[K]
? V // if `V` is `unknown` that means it does not extend `Ref` and is undefined
: T[K] extends Ref<infer V> | undefined
? unknown extends V ? undefined : V | undefined
: T[K]
}

export type UnwrapRef<T> = T extends ShallowRef<infer V>
Expand All @@ -303,7 +300,7 @@ export type UnwrapRefSimple<T> = T extends
| RefUnwrapBailTypes[keyof RefUnwrapBailTypes]
| { [RawSymbol]?: true }
? T
: T extends Array<any>
: T extends ReadonlyArray<any>
? { [K in keyof T]: UnwrapRefSimple<T[K]> }
: T extends object & { [ShallowReactiveMarker]?: never }
? {
Expand Down
135 changes: 73 additions & 62 deletions test-dts/reactivity.test-d.ts
@@ -1,62 +1,73 @@
import {
ref,
readonly,
shallowReadonly,
describe,
expectError,
expectType,
Ref,
reactive,
markRaw
} from './index'

describe('should support DeepReadonly', () => {
const r = readonly({ obj: { k: 'v' } })
// @ts-expect-error
expectError((r.obj = {}))
// @ts-expect-error
expectError((r.obj.k = 'x'))
})

// #4180
describe('readonly ref', () => {
const r = readonly(ref({ count: 1 }))
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
r.count = 2
expectType<Ref>(r.count.n)
r.count.n.value = 123
})
import {
ref,
readonly,
shallowReadonly,
describe,
expectError,
expectType,
Ref,
reactive,
markRaw
} from './index'

describe('should support DeepReadonly', () => {
const r = readonly({ obj: { k: 'v' } })
// @ts-expect-error
expectError((r.obj = {}))
// @ts-expect-error
expectError((r.obj.k = 'x'))
})

// #4180
describe('readonly ref', () => {
const r = readonly(ref({ count: 1 }))
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
r.count = 2
expectType<Ref>(r.count.n)
r.count.n.value = 123
})

// #3819
describe('should unwrap tuple correctly', () => {
const readonlyTuple = [ref(0)] as const
const reactiveReadonlyTuple = reactive(readonlyTuple)
expectType<Ref<number>>(reactiveReadonlyTuple[0])

const tuple: [Ref<number>] = [ref(0)]
const reactiveTuple = reactive(tuple)
expectType<Ref<number>>(reactiveTuple[0])
})

0 comments on commit e816812

Please sign in to comment.