types: improve UnwrapRef (#579)
This commit is contained in:
commit
e33291bd0e
@ -128,16 +128,44 @@ export function toRef<T extends object, K extends keyof T>(
|
|||||||
// RelativePath extends object -> true
|
// RelativePath extends object -> true
|
||||||
type BaseTypes = string | number | boolean | Node | Window
|
type BaseTypes = string | number | boolean | Node | Window
|
||||||
|
|
||||||
// Recursively unwraps nested value bindings.
|
export type UnwrapRef<T> = T extends ComputedRef<infer V>
|
||||||
export type UnwrapRef<T> = {
|
? UnwrapRefSimple<V>
|
||||||
cRef: T extends ComputedRef<infer V> ? UnwrapRef<V> : T
|
: T extends Ref<infer V> ? UnwrapRefSimple<V> : UnwrapRefSimple<T>
|
||||||
ref: T extends Ref<infer V> ? UnwrapRef<V> : T
|
|
||||||
array: T
|
type UnwrapRefSimple<T> = T extends Function | CollectionTypes | BaseTypes | Ref
|
||||||
object: { [K in keyof T]: UnwrapRef<T[K]> }
|
? T
|
||||||
}[T extends ComputedRef<any>
|
: T extends Array<any> ? T : T extends object ? UnwrappedObject<T> : T
|
||||||
? 'cRef'
|
|
||||||
: T extends Array<any>
|
// Extract all known symbols from an object
|
||||||
? 'array'
|
// when unwrapping Object the symbols are not `in keyof`, this should cover all the
|
||||||
: T extends Ref | Function | CollectionTypes | BaseTypes
|
// known symbols
|
||||||
? 'ref' // bail out on types that shouldn't be unwrapped
|
type SymbolExtract<T> = (T extends { [Symbol.asyncIterator]: infer V }
|
||||||
: T extends object ? 'object' : 'ref']
|
? { [Symbol.asyncIterator]: V }
|
||||||
|
: {}) &
|
||||||
|
(T extends { [Symbol.hasInstance]: infer V }
|
||||||
|
? { [Symbol.hasInstance]: V }
|
||||||
|
: {}) &
|
||||||
|
(T extends { [Symbol.isConcatSpreadable]: infer V }
|
||||||
|
? { [Symbol.isConcatSpreadable]: V }
|
||||||
|
: {}) &
|
||||||
|
(T extends { [Symbol.iterator]: infer V } ? { [Symbol.iterator]: V } : {}) &
|
||||||
|
(T extends { [Symbol.match]: infer V } ? { [Symbol.match]: V } : {}) &
|
||||||
|
(T extends { [Symbol.matchAll]: infer V } ? { [Symbol.matchAll]: V } : {}) &
|
||||||
|
(T extends { [Symbol.observable]: infer V }
|
||||||
|
? { [Symbol.observable]: V }
|
||||||
|
: {}) &
|
||||||
|
(T extends { [Symbol.replace]: infer V } ? { [Symbol.replace]: V } : {}) &
|
||||||
|
(T extends { [Symbol.search]: infer V } ? { [Symbol.search]: V } : {}) &
|
||||||
|
(T extends { [Symbol.species]: infer V } ? { [Symbol.species]: V } : {}) &
|
||||||
|
(T extends { [Symbol.split]: infer V } ? { [Symbol.split]: V } : {}) &
|
||||||
|
(T extends { [Symbol.toPrimitive]: infer V }
|
||||||
|
? { [Symbol.toPrimitive]: V }
|
||||||
|
: {}) &
|
||||||
|
(T extends { [Symbol.toStringTag]: infer V }
|
||||||
|
? { [Symbol.toStringTag]: V }
|
||||||
|
: {}) &
|
||||||
|
(T extends { [Symbol.unscopables]: infer V }
|
||||||
|
? { [Symbol.unscopables]: V }
|
||||||
|
: {})
|
||||||
|
|
||||||
|
type UnwrappedObject<T> = { [P in keyof T]: UnwrapRef<T[P]> } & SymbolExtract<T>
|
||||||
|
@ -4,7 +4,6 @@ import {
|
|||||||
h,
|
h,
|
||||||
render,
|
render,
|
||||||
nextTick,
|
nextTick,
|
||||||
Ref,
|
|
||||||
defineComponent,
|
defineComponent,
|
||||||
reactive
|
reactive
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
@ -143,7 +142,7 @@ describe('api: template refs', () => {
|
|||||||
foo: ref(null),
|
foo: ref(null),
|
||||||
bar: ref(null)
|
bar: ref(null)
|
||||||
}
|
}
|
||||||
const refKey = ref('foo') as Ref<keyof typeof refs>
|
const refKey = ref<keyof typeof refs>('foo')
|
||||||
|
|
||||||
const Comp = {
|
const Comp = {
|
||||||
setup() {
|
setup() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { expectType } from 'tsd'
|
import { expectType } from 'tsd'
|
||||||
import { Ref, ref, isRef, unref } from './index'
|
import { Ref, ref, isRef, unref, UnwrapRef } from './index'
|
||||||
|
|
||||||
function plainType(arg: number | Ref<number>) {
|
function plainType(arg: number | Ref<number>) {
|
||||||
// ref coercing
|
// ref coercing
|
||||||
@ -20,6 +20,16 @@ function plainType(arg: number | Ref<number>) {
|
|||||||
})
|
})
|
||||||
expectType<Ref<{ foo: number }>>(nestedRef)
|
expectType<Ref<{ foo: number }>>(nestedRef)
|
||||||
expectType<{ foo: number }>(nestedRef.value)
|
expectType<{ foo: number }>(nestedRef.value)
|
||||||
|
|
||||||
|
// tuple
|
||||||
|
expectType<[number, string]>(unref(ref([1, '1'])))
|
||||||
|
|
||||||
|
interface IteratorFoo {
|
||||||
|
[Symbol.iterator]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
// with symbol
|
||||||
|
expectType<IteratorFoo | null>(unref(ref<IteratorFoo | null>(null)))
|
||||||
}
|
}
|
||||||
|
|
||||||
plainType(1)
|
plainType(1)
|
||||||
|
Loading…
Reference in New Issue
Block a user