fix: don't freeze non-POJOs

The main reason for Object.freeze on `$state.frozen` is to mark a boundary for `$state` - but since that one doesn't traverse non-POJOs either, we should leave class instances etc alone, too.
Since "this is a POJO and not a class instance" cannot be described in typescript, the `Readonly` modifier had to be removed from the return type.
object-freeze-fix
Simon Holthausen 7 months ago
parent d061f2f137
commit 52414b9417

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: don't freeze non-POJOs

@ -19,7 +19,7 @@ declare function $state<T>(): T | undefined;
declare namespace $state {
/**
* Declares reactive read-only state that is shallowly immutable.
* Declares reactive read-only state that is shallowly immutable, if it's a plain object or array.
*
* Example:
* ```ts
@ -40,8 +40,8 @@ declare namespace $state {
*
* @param initial The initial value
*/
export function frozen<T>(initial: T): Readonly<T>;
export function frozen<T>(): Readonly<T> | undefined;
export function frozen<T>(initial: T): T;
export function frozen<T>(): T | undefined;
}
/**

@ -1301,12 +1301,16 @@ if (DEV) {
*/
export function freeze(value) {
if (typeof value === 'object' && value != null && !is_frozen(value)) {
// If the object is already proxified, then unstate the value
if (STATE_SYMBOL in value) {
return object_freeze(unstate(value));
const prototype = get_prototype_of(value);
// Leave class instances etc alone, they're not traversed by $state, either
if (prototype === object_prototype || prototype === array_prototype) {
// If the object is already proxified, then unstate the value
if (STATE_SYMBOL in value) {
return object_freeze(unstate(value));
}
// Otherwise freeze the object
object_freeze(value);
}
// Otherwise freeze the object
object_freeze(value);
}
return value;
}

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
html: `1`
});

@ -0,0 +1,9 @@
<script>
class Counter {
count = 0
}
const counter = $state.frozen(new Counter());
counter.count++;
</script>
{counter.count}

@ -2528,7 +2528,7 @@ declare function $state<T>(): T | undefined;
declare namespace $state {
/**
* Declares reactive read-only state that is shallowly immutable.
* Declares reactive read-only state that is shallowly immutable, if it's a plain object or array.
*
* Example:
* ```ts
@ -2549,8 +2549,8 @@ declare namespace $state {
*
* @param initial The initial value
*/
export function frozen<T>(initial: T): Readonly<T>;
export function frozen<T>(): Readonly<T> | undefined;
export function frozen<T>(initial: T): T;
export function frozen<T>(): T | undefined;
}
/**

Loading…
Cancel
Save