fix(reactivity): accept subtypes of collections (#1864)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { isObject, toRawType, def, hasOwn, makeMap } from '@vue/shared'
|
||||
import { isObject, toRawType, def, hasOwn } from '@vue/shared'
|
||||
import {
|
||||
mutableHandlers,
|
||||
readonlyHandlers,
|
||||
@@ -30,17 +30,31 @@ export interface Target {
|
||||
[ReactiveFlags.READONLY]?: any
|
||||
}
|
||||
|
||||
const collectionTypes = new Set<Function>([Set, Map, WeakMap, WeakSet])
|
||||
const isObservableType = /*#__PURE__*/ makeMap(
|
||||
'Object,Array,Map,Set,WeakMap,WeakSet'
|
||||
)
|
||||
const enum TargetType {
|
||||
INVALID = 0,
|
||||
COMMON = 1,
|
||||
COLLECTION = 2
|
||||
}
|
||||
|
||||
const canObserve = (value: Target): boolean => {
|
||||
return (
|
||||
!value[ReactiveFlags.SKIP] &&
|
||||
isObservableType(toRawType(value)) &&
|
||||
Object.isExtensible(value)
|
||||
)
|
||||
function targetTypeMap(rawType: string) {
|
||||
switch (rawType) {
|
||||
case 'Object':
|
||||
case 'Array':
|
||||
return TargetType.COMMON
|
||||
case 'Map':
|
||||
case 'Set':
|
||||
case 'WeakMap':
|
||||
case 'WeakSet':
|
||||
return TargetType.COLLECTION
|
||||
default:
|
||||
return TargetType.INVALID
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetType(value: Target) {
|
||||
return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
|
||||
? TargetType.INVALID
|
||||
: targetTypeMap(toRawType(value))
|
||||
}
|
||||
|
||||
// only unwrap nested ref
|
||||
@@ -148,12 +162,13 @@ function createReactiveObject(
|
||||
return target[reactiveFlag]
|
||||
}
|
||||
// only a whitelist of value types can be observed.
|
||||
if (!canObserve(target)) {
|
||||
const targetType = getTargetType(target)
|
||||
if (targetType === TargetType.INVALID) {
|
||||
return target
|
||||
}
|
||||
const observed = new Proxy(
|
||||
target,
|
||||
collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
|
||||
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
|
||||
)
|
||||
def(target, reactiveFlag, observed)
|
||||
return observed
|
||||
|
||||
Reference in New Issue
Block a user