This commit is contained in:
Özer 2025-05-05 20:38:29 +00:00 committed by GitHub
commit 8c7dcea619
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 97 additions and 2 deletions

View File

@ -112,6 +112,80 @@ describe('reactivity/reactive', () => {
expect(dummy).toBe(false)
})
test('reactive object with custom Symbol.toStringTag triggers reactivity', () => {
const original = { [Symbol.toStringTag]: 'Goat', foo: 1 }
const observed = reactive(original)
expect(isReactive(observed)).toBe(true)
expect(isProxy(observed)).toBe(true)
let dummy: number | undefined
effect(() => {
dummy = observed.foo
})
expect(dummy).toBe(1)
observed.foo = 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('custom array type with custom Symbol.toStringTag is handled as a common object', () => {
class MyArray extends Array {
get [Symbol.toStringTag]() {
return 'MyArray'
}
}
const myArr = new MyArray()
expect(Object.prototype.toString.call(myArr)).toBe('[object MyArray]')
const observed = reactive(myArr)
expect(isReactive(observed)).toBe(true)
expect(isProxy(observed)).toBe(true)
let dummy: number = 0
effect(() => {
dummy = observed.length
})
expect(dummy).toBe(0)
observed.push(42)
expect(dummy).toBe(1)
})
test('observed value should proxy mutations to original (Object)', () => {
const original: any = { foo: 1 }
const observed = reactive(original)

View File

@ -40,7 +40,8 @@ enum TargetType {
COLLECTION = 2,
}
function targetTypeMap(rawType: string) {
function targetTypeMap(value: Target): TargetType {
const rawType = toRawType(value)
switch (rawType) {
case 'Object':
case 'Array':
@ -51,14 +52,34 @@ function targetTypeMap(rawType: string) {
case 'WeakSet':
return TargetType.COLLECTION
default:
if (
value instanceof Map ||
value instanceof Set ||
value instanceof WeakMap ||
value instanceof WeakSet
) {
return TargetType.COLLECTION
}
if (value instanceof Array || isPlainObject(value)) {
return TargetType.COMMON
}
return TargetType.INVALID
}
}
function isPlainObject(value: unknown): value is object {
return (
typeof value === 'object' &&
value !== null &&
(Object.getPrototypeOf(value) === Object.prototype ||
Object.getPrototypeOf(value) === null)
)
}
function getTargetType(value: Target) {
return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
? TargetType.INVALID
: targetTypeMap(toRawType(value))
: targetTypeMap(value)
}
// only unwrap nested ref