mirror of https://github.com/vuejs/core.git
fix(reactivity): support custom Symbol.toStringTag for collections
This commit is contained in:
parent
d9444e5523
commit
b42d264da0
|
@ -130,6 +130,35 @@ describe('reactivity/reactive', () => {
|
||||||
expect(dummy).toBe(2)
|
expect(dummy).toBe(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('custom collection type with custom Symbol.toStringTag is handled as a collection', () => {
|
||||||
|
class MyCustomMap extends Map {
|
||||||
|
get [Symbol.toStringTag]() {
|
||||||
|
return 'MyCustomMap'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const myCustomMap = new MyCustomMap()
|
||||||
|
|
||||||
|
expect(Object.prototype.toString.call(myCustomMap)).toBe(
|
||||||
|
'[object MyCustomMap]',
|
||||||
|
)
|
||||||
|
|
||||||
|
const observed = reactive(myCustomMap)
|
||||||
|
|
||||||
|
expect(isReactive(observed)).toBe(true)
|
||||||
|
expect(isProxy(observed)).toBe(true)
|
||||||
|
|
||||||
|
let dummy: boolean = false
|
||||||
|
effect(() => {
|
||||||
|
dummy = observed.has('foo')
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(dummy).toBe(false)
|
||||||
|
|
||||||
|
observed.set('foo', 'bar')
|
||||||
|
expect(dummy).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
test('observed value should proxy mutations to original (Object)', () => {
|
test('observed value should proxy mutations to original (Object)', () => {
|
||||||
const original: any = { foo: 1 }
|
const original: any = { foo: 1 }
|
||||||
const observed = reactive(original)
|
const observed = reactive(original)
|
||||||
|
|
|
@ -68,14 +68,26 @@ function getTargetType(value: Target) {
|
||||||
if (value[ReactiveFlags.SKIP] || !Object.isExtensible(value)) {
|
if (value[ReactiveFlags.SKIP] || !Object.isExtensible(value)) {
|
||||||
return TargetType.INVALID
|
return TargetType.INVALID
|
||||||
}
|
}
|
||||||
const type = targetTypeMap(toRawType(value))
|
|
||||||
let type = targetTypeMap(rawType)
|
|
||||||
|
|
||||||
// If we got INVALID but the value is actually a plain object (even if its raw type was changed
|
let type = targetTypeMap(toRawType(value))
|
||||||
// by a custom Symbol.toStringTag), then force it to be reactive.
|
|
||||||
if (type === TargetType.INVALID && isPlainObject(value)) {
|
// If the raw type mapping fails, we add extra checks:
|
||||||
type = TargetType.COMMON
|
if (type === TargetType.INVALID) {
|
||||||
|
// Check for collection types even if they have a custom Symbol.toStringTag.
|
||||||
|
if (
|
||||||
|
value instanceof Map ||
|
||||||
|
value instanceof Set ||
|
||||||
|
value instanceof WeakMap ||
|
||||||
|
value instanceof WeakSet
|
||||||
|
) {
|
||||||
|
type = TargetType.COLLECTION
|
||||||
|
}
|
||||||
|
// Check if the value is a plain object despite a custom tag.
|
||||||
|
else if (isPlainObject(value)) {
|
||||||
|
type = TargetType.COMMON
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return type
|
return type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue