Skip to content

Commit c20d8af

Browse files
committed
types: add symbolExtract to extract all known symbols
#951
1 parent ab9add4 commit c20d8af

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

packages/reactivity/src/ref.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,12 @@ export type UnwrapRef<T> = T extends ComputedRef<infer V>
112112
? UnwrapRefSimple<V>
113113
: T extends Ref<infer V> ? UnwrapRefSimple<V> : UnwrapRefSimple<T>
114114

115-
type UnwrapRefSimple<T> = T extends Function | CollectionTypes | BaseTypes | Ref
115+
type UnwrapRefSimple<T> = T extends
116+
| Function
117+
| CollectionTypes
118+
| BaseTypes
119+
| Ref
120+
| Element
116121
? T
117122
: T extends Array<infer V>
118123
? Tupple<T> extends never ? Array<V> : UnwrapTupple<T>
@@ -124,6 +129,36 @@ export type UnwrapTupple<T> = { [P in keyof T]: T[P] } & {
124129
[Symbol.unscopables]: any
125130
}
126131

127-
// interface UnwrappedArray<T> extends Array<T> {}
128-
129-
type UnwrappedObject<T> = { [P in keyof T]: UnwrapRef<T[P]> }
132+
// Extract all known symbols from an object
133+
// when unwrapping Object the symbols are not `in keyof`, this should cover all the
134+
// known symbols
135+
type SymbolExtract<T> = (T extends { [Symbol.asyncIterator]: infer V }
136+
? { [Symbol.asyncIterator]: V }
137+
: {}) &
138+
(T extends { [Symbol.hasInstance]: infer V }
139+
? { [Symbol.hasInstance]: V }
140+
: {}) &
141+
(T extends { [Symbol.isConcatSpreadable]: infer V }
142+
? { [Symbol.isConcatSpreadable]: V }
143+
: {}) &
144+
(T extends { [Symbol.iterator]: infer V } ? { [Symbol.iterator]: V } : {}) &
145+
(T extends { [Symbol.match]: infer V } ? { [Symbol.match]: V } : {}) &
146+
(T extends { [Symbol.matchAll]: infer V } ? { [Symbol.matchAll]: V } : {}) &
147+
(T extends { [Symbol.observable]: infer V }
148+
? { [Symbol.observable]: V }
149+
: {}) &
150+
(T extends { [Symbol.replace]: infer V } ? { [Symbol.replace]: V } : {}) &
151+
(T extends { [Symbol.search]: infer V } ? { [Symbol.search]: V } : {}) &
152+
(T extends { [Symbol.species]: infer V } ? { [Symbol.species]: V } : {}) &
153+
(T extends { [Symbol.split]: infer V } ? { [Symbol.split]: V } : {}) &
154+
(T extends { [Symbol.toPrimitive]: infer V }
155+
? { [Symbol.toPrimitive]: V }
156+
: {}) &
157+
(T extends { [Symbol.toStringTag]: infer V }
158+
? { [Symbol.toStringTag]: V }
159+
: {}) &
160+
(T extends { [Symbol.unscopables]: infer V }
161+
? { [Symbol.unscopables]: V }
162+
: {})
163+
164+
type UnwrappedObject<T> = { [P in keyof T]: UnwrapRef<T[P]> } & SymbolExtract<T>

test-dts/ref.test-d.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expectType } from 'tsd'
2-
import { Ref, ref, isRef, unref } from './index'
2+
import { Ref, ref, isRef, unref, UnwrapRef } from './index'
33

44
function foo(arg: number | Ref<number>) {
55
// ref coercing
@@ -20,6 +20,15 @@ function foo(arg: number | Ref<number>) {
2020
})
2121
expectType<Ref<{ foo: number }>>(nestedRef)
2222
expectType<{ foo: number }>(nestedRef.value)
23+
24+
interface IteratorFoo {
25+
[Symbol.iterator]: any
26+
}
27+
expectType<Ref<UnwrapRef<IteratorFoo>> | Ref<null>>(
28+
ref<IteratorFoo | null>(null)
29+
)
30+
31+
expectType<Ref<HTMLElement> | Ref<null>>(ref<HTMLElement | null>(null))
2332
}
2433

2534
foo(1)

0 commit comments

Comments
 (0)