fix(reactivity): handle objects with custom Symbol.toStringTag

This commit is contained in:
Özer Gökalpsezer 2025-02-09 17:49:31 +03:00
parent 119f18c773
commit 30d1f32b83
2 changed files with 39 additions and 3 deletions

View File

@ -112,6 +112,24 @@ 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('observed value should proxy mutations to original (Object)', () => {
const original: any = { foo: 1 }
const observed = reactive(original)

View File

@ -55,10 +55,28 @@ function targetTypeMap(rawType: string) {
}
}
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))
if (value[ReactiveFlags.SKIP] || !Object.isExtensible(value)) {
return TargetType.INVALID
}
const rawType = 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
// by a custom Symbol.toStringTag), then force it to be reactive.
if (type === TargetType.INVALID && isPlainObject(value)) {
type = TargetType.COMMON
}
return type
}
// only unwrap nested ref