chore: refactor signal types (#10698)

- use interface instead of type (interface is less forgiving)
- rename SourceSignal to Source, etc
- make Derived extend Source, rather than deriveds sharing a type with effects, since they have much more in common with each other
- have a Value type which is a union of Source and Derived, and a Reaction type which is a union of Derived and Effect
- avoid using the Signal type (which is a union of all three) unless necessary
pull/10699/head
Rich Harris 10 months ago committed by GitHub
parent 0cc74e46fd
commit 86f326531c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -55,8 +55,8 @@ export function create_each_block(flags, anchor) {
} }
/** /**
* @param {any | import('../../types.js').Signal<any>} item * @param {any | import('../../types.js').Value<any>} item
* @param {number | import('../../types.js').Signal<number>} index * @param {number | import('../../types.js').Value<number>} index
* @param {null | unknown} key * @param {null | unknown} key
* @returns {import('../../types.js').EachItemBlock} * @returns {import('../../types.js').EachItemBlock}
*/ */
@ -110,7 +110,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
/** @type {Array<string> | null} */ /** @type {Array<string> | null} */
let keys = null; let keys = null;
/** @type {null | import('../../types.js').EffectSignal} */ /** @type {null | import('../../types.js').Effect} */
let render = null; let render = null;
/** /**
@ -279,7 +279,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
} }
// Clear the array // Clear the array
reconcile_fn([], block, anchor_node, is_controlled, render_fn, flags, false, keys); reconcile_fn([], block, anchor_node, is_controlled, render_fn, flags, false, keys);
destroy_signal(/** @type {import('../../types.js').EffectSignal} */ (render)); destroy_signal(/** @type {import('../../types.js').Effect} */ (render));
}); });
block.e = each; block.e = each;
@ -318,7 +318,7 @@ export function each_indexed(anchor_node, collection, flags, render_fn, fallback
* @param {import('../../types.js').EachBlock} each_block * @param {import('../../types.js').EachBlock} each_block
* @param {Element | Comment | Text} dom * @param {Element | Comment | Text} dom
* @param {boolean} is_controlled * @param {boolean} is_controlled
* @param {(anchor: null, item: V, index: number | import('../../types.js').Signal<number>) => void} render_fn * @param {(anchor: null, item: V, index: number | import('../../types.js').Source<number>) => void} render_fn
* @param {number} flags * @param {number} flags
* @param {boolean} apply_transitions * @param {boolean} apply_transitions
* @returns {void} * @returns {void}
@ -433,7 +433,7 @@ function reconcile_indexed_array(
* @param {import('../../types.js').EachBlock} each_block * @param {import('../../types.js').EachBlock} each_block
* @param {Element | Comment | Text} dom * @param {Element | Comment | Text} dom
* @param {boolean} is_controlled * @param {boolean} is_controlled
* @param {(anchor: null, item: V, index: number | import('../../types.js').Signal<number>) => void} render_fn * @param {(anchor: null, item: V, index: number | import('../../types.js').Source<number>) => void} render_fn
* @param {number} flags * @param {number} flags
* @param {boolean} apply_transitions * @param {boolean} apply_transitions
* @param {Array<string> | null} keys * @param {Array<string> | null} keys
@ -848,7 +848,7 @@ function update_each_item_block(block, item, index, type) {
each_animation(block, transitions); each_animation(block, transitions);
} }
if (index_is_reactive) { if (index_is_reactive) {
set(/** @type {import('../../types.js').Signal<number>} */ (block.i), index); set(/** @type {import('../../types.js').Value<number>} */ (block.i), index);
} else { } else {
block.i = index; block.i = index;
} }
@ -890,7 +890,7 @@ export function destroy_each_item_block(
if (!controlled && dom !== null) { if (!controlled && dom !== null) {
remove(dom); remove(dom);
} }
destroy_signal(/** @type {import('../../types.js').EffectSignal} */ (block.e)); destroy_signal(/** @type {import('../../types.js').Effect} */ (block.e));
} }
/** /**
@ -898,7 +898,7 @@ export function destroy_each_item_block(
* @param {V} item * @param {V} item
* @param {unknown} key * @param {unknown} key
* @param {number} index * @param {number} index
* @param {(anchor: null, item: V, index: number | import('../../types.js').Signal<number>) => void} render_fn * @param {(anchor: null, item: V, index: number | import('../../types.js').Value<number>) => void} render_fn
* @param {number} flags * @param {number} flags
* @returns {import('../../types.js').EachItemBlock} * @returns {import('../../types.js').EachItemBlock}
*/ */

@ -55,7 +55,7 @@ export function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn)
let alternate_dom = null; let alternate_dom = null;
let has_mounted = false; let has_mounted = false;
/** /**
* @type {import('../../types.js').EffectSignal | null} * @type {import('../../types.js').Effect | null}
*/ */
let current_branch_effect = null; let current_branch_effect = null;
@ -117,7 +117,7 @@ export function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn)
const consequent_effect = render_effect( const consequent_effect = render_effect(
( (
/** @type {any} */ _, /** @type {any} */ _,
/** @type {import('../../types.js').EffectSignal | null} */ consequent_effect /** @type {import('../../types.js').Effect | null} */ consequent_effect
) => { ) => {
const result = block.v; const result = block.v;
if (!result && consequent_dom !== null) { if (!result && consequent_dom !== null) {
@ -143,7 +143,7 @@ export function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn)
const alternate_effect = render_effect( const alternate_effect = render_effect(
( (
/** @type {any} */ _, /** @type {any} */ _,
/** @type {import('../../types.js').EffectSignal | null} */ alternate_effect /** @type {import('../../types.js').Effect | null} */ alternate_effect
) => { ) => {
const result = block.v; const result = block.v;
if (result && alternate_dom !== null) { if (result && alternate_dom !== null) {

@ -148,7 +148,7 @@ export function unstate(value) {
} }
/** /**
* @param {import('./types.js').Signal<number>} signal * @param {import('./types.js').Source<number>} signal
* @param {1 | -1} [d] * @param {1 | -1} [d]
*/ */
function update_version(signal, d = 1) { function update_version(signal, d = 1) {

@ -1,32 +1,48 @@
import { DEV } from 'esm-env';
import { CLEAN, DERIVED, UNINITIALIZED, UNOWNED } from '../constants.js'; import { CLEAN, DERIVED, UNINITIALIZED, UNOWNED } from '../constants.js';
import { current_block, current_consumer, current_effect } from '../runtime.js'; import { current_block, current_consumer, current_effect } from '../runtime.js';
import { create_computation_signal, push_reference } from './effects.js'; import { push_reference } from './effects.js';
import { default_equals, safe_equal } from './equality.js'; import { default_equals, safe_equal } from './equality.js';
/** /**
* @template V * @template V
* @param {() => V} fn * @param {() => V} fn
* @returns {import('../types.js').ComputationSignal<V>} * @returns {import('../types.js').Derived<V>}
*/ */
/*#__NO_SIDE_EFFECTS__*/ /*#__NO_SIDE_EFFECTS__*/
export function derived(fn) { export function derived(fn) {
const is_unowned = current_effect === null; const is_unowned = current_effect === null;
const flags = is_unowned ? DERIVED | UNOWNED : DERIVED; const flags = is_unowned ? DERIVED | UNOWNED : DERIVED;
const signal = /** @type {import('../types.js').ComputationSignal<V>} */ ( const signal = /** @type {import('../types.js').Derived<V>} */ ({
create_computation_signal(flags | CLEAN, UNINITIALIZED, current_block) b: current_block,
); c: null,
signal.i = fn; d: null,
signal.e = default_equals; e: default_equals,
f: flags | CLEAN,
i: fn,
r: null,
v: UNINITIALIZED,
w: 0,
x: null,
y: null
});
if (DEV) {
// @ts-expect-error
signal.inspect = new Set();
}
if (current_consumer !== null) { if (current_consumer !== null) {
push_reference(current_consumer, signal); push_reference(current_consumer, signal);
} }
return signal; return signal;
} }
/** /**
* @template V * @template V
* @param {() => V} fn * @param {() => V} fn
* @returns {import('../types.js').ComputationSignal<V>} * @returns {import('../types.js').Derived<V>}
*/ */
/*#__NO_SIDE_EFFECTS__*/ /*#__NO_SIDE_EFFECTS__*/
export function derived_safe_equal(fn) { export function derived_safe_equal(fn) {

@ -2,59 +2,16 @@ import { DEV } from 'esm-env';
import { import {
current_block, current_block,
current_component_context, current_component_context,
current_consumer,
current_effect, current_effect,
destroy_signal, destroy_signal,
flush_local_render_effects, flush_local_render_effects,
schedule_effect schedule_effect
} from '../runtime.js'; } from '../runtime.js';
import { default_equals, safe_equal } from './equality.js'; import { DIRTY, MANAGED, RENDER_EFFECT, EFFECT, PRE_EFFECT } from '../constants.js';
import {
DIRTY,
MANAGED,
RENDER_EFFECT,
EFFECT,
PRE_EFFECT,
DERIVED,
UNOWNED,
CLEAN,
UNINITIALIZED
} from '../constants.js';
/**
* @template V
* @param {import('../types.js').SignalFlags} flags
* @param {V} value
* @param {import('../types.js').Block | null} block
*/
export function create_computation_signal(flags, value, block) {
/** @type {import('../types.js').ComputationSignal<V>} */
const signal = {
b: block,
c: null,
d: null,
e: null,
f: flags,
l: 0,
i: null,
r: null,
v: value,
w: 0,
x: null,
y: null
};
if (DEV) {
// @ts-expect-error
signal.inspect = new Set();
}
return signal;
}
/** /**
* @param {import('../types.js').ComputationSignal} target_signal * @param {import('../types.js').Reaction} target_signal
* @param {import('../types.js').ComputationSignal} ref_signal * @param {import('../types.js').Reaction} ref_signal
* @returns {void} * @returns {void}
*/ */
export function push_reference(target_signal, ref_signal) { export function push_reference(target_signal, ref_signal) {
@ -72,12 +29,25 @@ export function push_reference(target_signal, ref_signal) {
* @param {boolean} sync * @param {boolean} sync
* @param {null | import('../types.js').Block} block * @param {null | import('../types.js').Block} block
* @param {boolean} schedule * @param {boolean} schedule
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
function internal_create_effect(type, fn, sync, block, schedule) { function internal_create_effect(type, fn, sync, block, schedule) {
const signal = create_computation_signal(type | DIRTY, null, block); /** @type {import('#client').Effect} */
signal.i = fn; const signal = {
signal.x = current_component_context; b: block,
c: null,
d: null,
e: null,
f: type | DIRTY,
l: 0,
i: fn,
r: null,
v: null,
w: 0,
x: current_component_context,
y: null
};
if (current_effect !== null) { if (current_effect !== null) {
signal.l = current_effect.l + 1; signal.l = current_effect.l + 1;
if ((type & MANAGED) === 0) { if ((type & MANAGED) === 0) {
@ -100,7 +70,7 @@ export function effect_active() {
/** /**
* Internal representation of `$effect(...)` * Internal representation of `$effect(...)`
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function user_effect(fn) { export function user_effect(fn) {
if (current_effect === null) { if (current_effect === null) {
@ -147,7 +117,7 @@ export function user_root_effect(fn) {
/** /**
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function effect(fn) { export function effect(fn) {
return internal_create_effect(EFFECT, fn, false, current_block, true); return internal_create_effect(EFFECT, fn, false, current_block, true);
@ -155,7 +125,7 @@ export function effect(fn) {
/** /**
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function managed_effect(fn) { export function managed_effect(fn) {
return internal_create_effect(EFFECT | MANAGED, fn, false, current_block, true); return internal_create_effect(EFFECT | MANAGED, fn, false, current_block, true);
@ -164,7 +134,7 @@ export function managed_effect(fn) {
/** /**
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
* @param {boolean} sync * @param {boolean} sync
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function managed_pre_effect(fn, sync) { export function managed_pre_effect(fn, sync) {
return internal_create_effect(PRE_EFFECT | MANAGED, fn, sync, current_block, true); return internal_create_effect(PRE_EFFECT | MANAGED, fn, sync, current_block, true);
@ -173,7 +143,7 @@ export function managed_pre_effect(fn, sync) {
/** /**
* Internal representation of `$effect.pre(...)` * Internal representation of `$effect.pre(...)`
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function pre_effect(fn) { export function pre_effect(fn) {
if (current_effect === null) { if (current_effect === null) {
@ -203,7 +173,7 @@ export function pre_effect(fn) {
* bindings which are in later effects. However, we don't use a pre_effect directly as we don't want to flush anything. * bindings which are in later effects. However, we don't use a pre_effect directly as we don't want to flush anything.
* *
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function invalidate_effect(fn) { export function invalidate_effect(fn) {
return internal_create_effect(PRE_EFFECT, fn, true, current_block, true); return internal_create_effect(PRE_EFFECT, fn, true, current_block, true);
@ -215,7 +185,7 @@ export function invalidate_effect(fn) {
* @param {any} block * @param {any} block
* @param {any} managed * @param {any} managed
* @param {any} sync * @param {any} sync
* @returns {import('../types.js').EffectSignal} * @returns {import('../types.js').Effect}
*/ */
export function render_effect(fn, block = current_block, managed = false, sync = true) { export function render_effect(fn, block = current_block, managed = false, sync = true) {
let flags = RENDER_EFFECT; let flags = RENDER_EFFECT;

@ -24,17 +24,30 @@ import { CLEAN, DERIVED, DIRTY, MANAGED, SOURCE } from '../constants.js';
/** /**
* @template V * @template V
* @param {V} initial_value * @param {V} initial_value
* @returns {import('../types.js').SourceSignal<V>} * @returns {import('../types.js').Source<V>}
*/ */
/*#__NO_SIDE_EFFECTS__*/ /*#__NO_SIDE_EFFECTS__*/
export function source(initial_value) { export function source(initial_value) {
return create_source_signal(SOURCE | CLEAN, initial_value); /** @type {import('#client').Source<V>} */
const signal = {
c: null,
e: default_equals,
f: SOURCE | CLEAN,
v: initial_value,
w: 0
};
if (DEV) {
/** @type {import('#client').SourceDebug} */ (signal).inspect = new Set();
}
return signal;
} }
/** /**
* @template V * @template V
* @param {V} initial_value * @param {V} initial_value
* @returns {import('../types.js').SourceSignal<V>} * @returns {import('../types.js').Source<V>}
*/ */
/*#__NO_SIDE_EFFECTS__*/ /*#__NO_SIDE_EFFECTS__*/
export function mutable_source(initial_value) { export function mutable_source(initial_value) {
@ -52,44 +65,7 @@ export function mutable_source(initial_value) {
/** /**
* @template V * @template V
* @param {import('../types.js').SignalFlags} flags * @param {import('./types.js').Source<V>} signal
* @param {V} value
* @returns {import('../types.js').SourceSignal<V> | import('../types.js').SourceSignal<V> & import('../types.js').SourceSignalDebug}
*/
function create_source_signal(flags, value) {
if (DEV) {
return {
// consumers
c: null,
// equals
e: default_equals,
// flags
f: flags,
// value
v: value,
// write version
w: 0,
// this is for DEV only
inspect: new Set()
};
}
return {
// consumers
c: null,
// equals
e: default_equals,
// flags
f: flags,
// value
v: value,
// write version
w: 0
};
}
/**
* @template V
* @param {import('./types.js').Signal<V>} signal
* @param {V} value * @param {V} value
* @returns {void} * @returns {void}
*/ */
@ -99,7 +75,7 @@ export function set_sync(signal, value) {
/** /**
* @template V * @template V
* @param {import('./types.js').Signal<V>} source * @param {import('./types.js').Value<V>} source
* @param {V} value * @param {V} value
*/ */
export function mutate(source, value) { export function mutate(source, value) {
@ -112,7 +88,7 @@ export function mutate(source, value) {
/** /**
* @template V * @template V
* @param {import('./types.js').Signal<V>} signal * @param {import('./types.js').Source<V>} signal
* @param {V} value * @param {V} value
* @returns {V} * @returns {V}
*/ */
@ -174,9 +150,9 @@ export function set(signal, value) {
// @ts-expect-error // @ts-expect-error
if (DEV && signal.inspect) { if (DEV && signal.inspect) {
if (is_batching_effect) { if (is_batching_effect) {
set_last_inspected_signal(/** @type {import('./types.js').SignalDebug} */ (signal)); set_last_inspected_signal(/** @type {import('./types.js').ValueDebug} */ (signal));
} else { } else {
for (const fn of /** @type {import('./types.js').SignalDebug} */ (signal).inspect) fn(); for (const fn of /** @type {import('./types.js').ValueDebug} */ (signal).inspect) fn();
} }
} }
} }

@ -50,7 +50,7 @@ export function store_get(store, store_name, stores) {
/** /**
* @template V * @template V
* @param {import('../types.js').Store<V> | null | undefined} store * @param {import('../types.js').Store<V> | null | undefined} store
* @param {import('../types.js').SourceSignal<V>} source * @param {import('../types.js').Source<V>} source
*/ */
function connect_store_to_signal(store, source) { function connect_store_to_signal(store, source) {
if (store == null) { if (store == null) {

@ -9,14 +9,9 @@ export type SignalFlags =
| typeof RENDER_EFFECT; | typeof RENDER_EFFECT;
export type EffectType = typeof EFFECT | typeof PRE_EFFECT | typeof RENDER_EFFECT; export type EffectType = typeof EFFECT | typeof PRE_EFFECT | typeof RENDER_EFFECT;
// We keep two shapes rather than a single monomorphic shape to improve the memory usage. export interface Source<V = unknown> {
// Source signals don't need the same shape as they simply don't do as much as computations
// (effects and derived signals). Thus we can improve the memory profile at the slight cost
// of some runtime performance.
export type SourceSignal<V = unknown> = {
/** consumers: Signals that read from the current signal */ /** consumers: Signals that read from the current signal */
c: null | ComputationSignal[]; c: null | Reaction[];
/** equals: For value equality */ /** equals: For value equality */
e: null | EqualsFunctions; e: null | EqualsFunctions;
/** flags: The types that the signal represent, as a bitwise value */ /** flags: The types that the signal represent, as a bitwise value */
@ -25,50 +20,70 @@ export type SourceSignal<V = unknown> = {
v: V; v: V;
// write version // write version
w: number; w: number;
}; }
export type SourceSignalDebug = { export interface SourceDebug<V = unknown> extends Source<V> {
/** This is DEV only */
inspect: Set<Function>; inspect: Set<Function>;
}; }
export interface Derived<V = unknown> extends Source<V> {
/** dependencies: Signals that this signal reads from */
d: null | Value[];
/** The derived function */
i: () => V;
// TODO get rid of these
/** references: Anything that a signal owns */
r: null | Reaction[];
/** block: The block associated with this effect/computed */
b: null | Block;
/** context: The associated component if this signal is an effect/computed */
x: null | ComponentContext;
/** destroy: Thing(s) that need destroying */
y: null | (() => void) | Array<() => void>;
}
export type ComputationSignal<V = unknown> = { export interface DerivedDebug<V = unknown> extends Derived<V> {
inspect: Set<Function>;
}
export type Effect = {
/** block: The block associated with this effect/computed */ /** block: The block associated with this effect/computed */
b: null | Block; b: null | Block;
/** consumers: Signals that read from the current signal */ /** consumers: Signals that read from the current signal */
c: null | ComputationSignal[]; c: null | Reaction[];
/** context: The associated component if this signal is an effect/computed */ /** context: The associated component if this signal is an effect/computed */
x: null | ComponentContext; x: null | ComponentContext;
/** dependencies: Signals that this signal reads from */ /** dependencies: Signals that this signal reads from */
d: null | Signal<V>[]; d: null | Value[];
/** destroy: Thing(s) that need destroying */ /** destroy: Thing(s) that need destroying */
// TODO simplify this, it is only used in one place
y: null | (() => void) | Array<() => void>; y: null | (() => void) | Array<() => void>;
/** equals: For value equality */ /** equals: For value equality */
e: null | EqualsFunctions; e: null | EqualsFunctions;
/** The types that the signal represent, as a bitwise value */ /** The types that the signal represent, as a bitwise value */
f: SignalFlags; f: SignalFlags;
/** init: The function that we invoke for effects and computeds */ /** init: The function that we invoke for effects and computeds */
i: i: null | (() => void | (() => void)) | ((b: Block, s: Signal) => void | (() => void));
| null
| (() => V)
| (() => void | (() => void))
| ((b: Block, s: Signal) => void | (() => void));
/** references: Anything that a signal owns */ /** references: Anything that a signal owns */
r: null | ComputationSignal[]; r: null | Reaction[];
/** value: The latest value for this signal, doubles as the teardown for effects */ /** value: The latest value for this signal, doubles as the teardown for effects */
v: V; v: null | Function;
/** level: the depth from the root signal, used for ordering render/pre-effects topologically **/ /** level: the depth from the root signal, used for ordering render/pre-effects topologically **/
l: number; l: number;
/** write version: used for unowned signals to track if their depdendencies are dirty or not **/ /** write version: used for unowned signals to track if their depdendencies are dirty or not **/
w: number; w: number;
}; };
export type Signal<V = unknown> = SourceSignal<V> | ComputationSignal<V>; export type Reaction = Derived | Effect;
export type Signal<V = unknown> = Source<V> | Reaction;
export type SignalDebug<V = unknown> = SourceSignalDebug & Signal<V>; export type MaybeSignal<T = unknown> = T | Source<T>;
export type EffectSignal = ComputationSignal<null | (() => void)>; export type UnwrappedSignal<T> = T extends Value<infer U> ? U : T;
export type MaybeSignal<T = unknown> = T | Signal<T>; export type Value<V = unknown> = Source<V> | Derived<V>;
export type UnwrappedSignal<T> = T extends Signal<infer U> ? U : T; export type ValueDebug<V = unknown> = SourceDebug<V> | DerivedDebug<V>;

@ -727,7 +727,7 @@ export function bind_playback_rate(media, get_value, update) {
// Needs to happen after the element is inserted into the dom, else playback will be set back to 1 by the browser. // Needs to happen after the element is inserted into the dom, else playback will be set back to 1 by the browser.
// For hydration we could do it immediately but the additional code is not worth the lost microtask. // For hydration we could do it immediately but the additional code is not worth the lost microtask.
/** @type {import('./types.js').ComputationSignal | undefined} */ /** @type {import('./types.js').Reaction | undefined} */
let render; let render;
let destroyed = false; let destroyed = false;
const effect = managed_effect(() => { const effect = managed_effect(() => {
@ -2384,7 +2384,7 @@ const rest_props_handler = {
}; };
/** /**
* @param {import('./types.js').Signal<Record<string, unknown>> | Record<string, unknown>} props * @param {Record<string, unknown>} props
* @param {string[]} rest * @param {string[]} rest
* @returns {Record<string, unknown>} * @returns {Record<string, unknown>}
*/ */
@ -2647,7 +2647,7 @@ function _mount(Component, options) {
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
} }
destroy_signal(/** @type {import('./types.js').EffectSignal} */ (block.e)); destroy_signal(/** @type {import('./types.js').Effect} */ (block.e));
}); });
return component; return component;

@ -48,40 +48,40 @@ let is_inspecting_signal = false;
// Handle effect queues // Handle effect queues
/** @type {import('./types.js').EffectSignal[]} */ /** @type {import('./types.js').Effect[]} */
let current_queued_pre_and_render_effects = []; let current_queued_pre_and_render_effects = [];
/** @type {import('./types.js').EffectSignal[]} */ /** @type {import('./types.js').Effect[]} */
let current_queued_effects = []; let current_queued_effects = [];
let flush_count = 0; let flush_count = 0;
// Handle signal reactivity tree dependencies and consumer // Handle signal reactivity tree dependencies and consumer
/** @type {null | import('./types.js').ComputationSignal} */ /** @type {null | import('./types.js').Reaction} */
export let current_consumer = null; export let current_consumer = null;
/** @type {null | import('./types.js').EffectSignal} */ /** @type {null | import('./types.js').Effect} */
export let current_effect = null; export let current_effect = null;
/** @type {null | import('./types.js').Signal[]} */ /** @type {null | import('./types.js').Value[]} */
export let current_dependencies = null; export let current_dependencies = null;
let current_dependencies_index = 0; let current_dependencies_index = 0;
/** /**
* Tracks writes that the effect it's executed in doesn't listen to yet, * Tracks writes that the effect it's executed in doesn't listen to yet,
* so that the dependency can be added to the effect later on if it then reads it * so that the dependency can be added to the effect later on if it then reads it
* @type {null | import('./types.js').Signal[]} * @type {null | import('./types.js').Source[]}
*/ */
export let current_untracked_writes = null; export let current_untracked_writes = null;
/** @param {null | import('./types.js').Signal[]} value */ /** @param {null | import('./types.js').Source[]} value */
export function set_current_untracked_writes(value) { export function set_current_untracked_writes(value) {
current_untracked_writes = value; current_untracked_writes = value;
} }
/** @type {null | import('./types.js').SignalDebug} */ /** @type {null | import('./types.js').ValueDebug} */
export let last_inspected_signal = null; export let last_inspected_signal = null;
/** @param {null | import('./types.js').SignalDebug} signal */ /** @param {null | import('./types.js').ValueDebug} signal */
export function set_last_inspected_signal(signal) { export function set_last_inspected_signal(signal) {
last_inspected_signal = signal; last_inspected_signal = signal;
} }
@ -105,7 +105,7 @@ let captured_signals = new Set();
/** @type {Function | null} */ /** @type {Function | null} */
export let inspect_fn = null; export let inspect_fn = null;
/** @type {Array<import('./types.js').SignalDebug>} */ /** @type {Array<import('./types.js').ValueDebug>} */
let inspect_captured_signals = []; let inspect_captured_signals = [];
// Handle rendering tree blocks and anchors // Handle rendering tree blocks and anchors
@ -160,8 +160,7 @@ export function batch_inspect(target, prop, receiver) {
} }
/** /**
* @template V * @param {import('./types.js').Signal} signal
* @param {import('./types.js').Signal<V>} signal
* @returns {boolean} * @returns {boolean}
*/ */
function is_signal_dirty(signal) { function is_signal_dirty(signal) {
@ -170,7 +169,7 @@ function is_signal_dirty(signal) {
return true; return true;
} }
if ((flags & MAYBE_DIRTY) !== 0) { if ((flags & MAYBE_DIRTY) !== 0) {
const dependencies = /** @type {import('./types.js').ComputationSignal<V>} **/ (signal).d; const dependencies = /** @type {import('./types.js').Reaction} **/ (signal).d;
if (dependencies !== null) { if (dependencies !== null) {
const length = dependencies.length; const length = dependencies.length;
let i; let i;
@ -183,10 +182,7 @@ function is_signal_dirty(signal) {
// The flags can be marked as dirty from the above is_signal_dirty call. // The flags can be marked as dirty from the above is_signal_dirty call.
if ((dependency.f & DIRTY) !== 0) { if ((dependency.f & DIRTY) !== 0) {
if ((dependency.f & DERIVED) !== 0) { if ((dependency.f & DERIVED) !== 0) {
update_derived( update_derived(/** @type {import('./types.js').Derived} **/ (dependency), true);
/** @type {import('./types.js').ComputationSignal<V>} **/ (dependency),
true
);
// Might have been mutated from above get. // Might have been mutated from above get.
if ((signal.f & DIRTY) !== 0) { if ((signal.f & DIRTY) !== 0) {
return true; return true;
@ -214,7 +210,7 @@ function is_signal_dirty(signal) {
/** /**
* @template V * @template V
* @param {import('./types.js').ComputationSignal<V>} signal * @param {import('./types.js').Reaction} signal
* @returns {V} * @returns {V}
*/ */
function execute_signal_fn(signal) { function execute_signal_fn(signal) {
@ -229,7 +225,7 @@ function execute_signal_fn(signal) {
const previous_skip_consumer = current_skip_consumer; const previous_skip_consumer = current_skip_consumer;
const is_render_effect = (flags & RENDER_EFFECT) !== 0; const is_render_effect = (flags & RENDER_EFFECT) !== 0;
const previous_untracking = current_untracking; const previous_untracking = current_untracking;
current_dependencies = /** @type {null | import('./types.js').Signal[]} */ (null); current_dependencies = /** @type {null | import('./types.js').Value[]} */ (null);
current_dependencies_index = 0; current_dependencies_index = 0;
current_untracked_writes = null; current_untracked_writes = null;
current_consumer = signal; current_consumer = signal;
@ -251,7 +247,7 @@ function execute_signal_fn(signal) {
} else { } else {
res = /** @type {() => V} */ (init)(); res = /** @type {() => V} */ (init)();
} }
let dependencies = /** @type {import('./types.js').Signal<unknown>[]} **/ (signal.d); let dependencies = /** @type {import('./types.js').Value<unknown>[]} **/ (signal.d);
if (current_dependencies !== null) { if (current_dependencies !== null) {
let i; let i;
if (dependencies !== null) { if (dependencies !== null) {
@ -286,7 +282,7 @@ function execute_signal_fn(signal) {
dependencies[current_dependencies_index + i] = current_dependencies[i]; dependencies[current_dependencies_index + i] = current_dependencies[i];
} }
} else { } else {
signal.d = /** @type {import('./types.js').Signal<V>[]} **/ ( signal.d = /** @type {import('./types.js').Value<V>[]} **/ (
dependencies = current_dependencies dependencies = current_dependencies
); );
} }
@ -326,8 +322,8 @@ function execute_signal_fn(signal) {
/** /**
* @template V * @template V
* @param {import('./types.js').ComputationSignal<V>} signal * @param {import('./types.js').Reaction} signal
* @param {import('./types.js').Signal<V>} dependency * @param {import('./types.js').Value<V>} dependency
* @returns {void} * @returns {void}
*/ */
function remove_consumer(signal, dependency) { function remove_consumer(signal, dependency) {
@ -349,13 +345,12 @@ function remove_consumer(signal, dependency) {
if (consumers_length === 0 && (dependency.f & UNOWNED) !== 0) { if (consumers_length === 0 && (dependency.f & UNOWNED) !== 0) {
// If the signal is unowned then we need to make sure to change it to dirty. // If the signal is unowned then we need to make sure to change it to dirty.
set_signal_status(dependency, DIRTY); set_signal_status(dependency, DIRTY);
remove_consumers(/** @type {import('./types.js').ComputationSignal<V>} **/ (dependency), 0); remove_consumers(/** @type {import('./types.js').Reaction} **/ (dependency), 0);
} }
} }
/** /**
* @template V * @param {import('./types.js').Reaction} signal
* @param {import('./types.js').ComputationSignal<V>} signal
* @param {number} start_index * @param {number} start_index
* @returns {void} * @returns {void}
*/ */
@ -375,8 +370,7 @@ function remove_consumers(signal, start_index) {
} }
/** /**
* @template V * @param {import('./types.js').Reaction} signal
* @param {import('./types.js').ComputationSignal<V>} signal
* @returns {void} * @returns {void}
*/ */
function destroy_references(signal) { function destroy_references(signal) {
@ -405,7 +399,7 @@ function report_error(block, error) {
} }
/** /**
* @param {import('./types.js').EffectSignal} signal * @param {import('./types.js').Effect} signal
* @returns {void} * @returns {void}
*/ */
export function execute_effect(signal) { export function execute_effect(signal) {
@ -460,7 +454,7 @@ function infinite_loop_guard() {
} }
/** /**
* @param {Array<import('./types.js').EffectSignal>} effects * @param {Array<import('./types.js').Effect>} effects
* @returns {void} * @returns {void}
*/ */
function flush_queued_effects(effects) { function flush_queued_effects(effects) {
@ -508,7 +502,7 @@ function process_microtask() {
} }
/** /**
* @param {import('./types.js').EffectSignal} signal * @param {import('./types.js').Effect} signal
* @param {boolean} sync * @param {boolean} sync
* @returns {void} * @returns {void}
*/ */
@ -640,10 +634,10 @@ export function flush_sync(fn, flush_previous = true) {
try { try {
infinite_loop_guard(); infinite_loop_guard();
/** @type {import('./types.js').EffectSignal[]} */ /** @type {import('./types.js').Effect[]} */
const pre_and_render_effects = []; const pre_and_render_effects = [];
/** @type {import('./types.js').EffectSignal[]} */ /** @type {import('./types.js').Effect[]} */
const effects = []; const effects = [];
current_scheduler_mode = FLUSH_SYNC; current_scheduler_mode = FLUSH_SYNC;
current_queued_pre_and_render_effects = pre_and_render_effects; current_queued_pre_and_render_effects = pre_and_render_effects;
@ -681,8 +675,7 @@ export async function tick() {
} }
/** /**
* @template V * @param {import('./types.js').Derived} signal
* @param {import('./types.js').ComputationSignal<V>} signal
* @param {boolean} force_schedule * @param {boolean} force_schedule
* @returns {void} * @returns {void}
*/ */
@ -704,20 +697,20 @@ function update_derived(signal, force_schedule) {
// @ts-expect-error // @ts-expect-error
if (DEV && signal.inspect && force_schedule) { if (DEV && signal.inspect && force_schedule) {
for (const fn of /** @type {import('./types.js').SignalDebug} */ (signal).inspect) fn(); for (const fn of /** @type {import('./types.js').ValueDebug} */ (signal).inspect) fn();
} }
} }
} }
/** /**
* @template V * @template V
* @param {import('./types.js').Signal<V>} signal * @param {import('./types.js').Value<V>} signal
* @returns {V} * @returns {V}
*/ */
export function get(signal) { export function get(signal) {
// @ts-expect-error // @ts-expect-error
if (DEV && signal.inspect && inspect_fn) { if (DEV && signal.inspect && inspect_fn) {
/** @type {import('./types.js').SignalDebug} */ (signal).inspect.add(inspect_fn); /** @type {import('./types.js').ValueDebug} */ (signal).inspect.add(inspect_fn);
// @ts-expect-error // @ts-expect-error
inspect_captured_signals.push(signal); inspect_captured_signals.push(signal);
} }
@ -770,10 +763,10 @@ export function get(signal) {
// we want to avoid tracking indirect dependencies // we want to avoid tracking indirect dependencies
const previous_inspect_fn = inspect_fn; const previous_inspect_fn = inspect_fn;
inspect_fn = null; inspect_fn = null;
update_derived(/** @type {import('./types.js').ComputationSignal<V>} **/ (signal), false); update_derived(/** @type {import('./types.js').Derived} **/ (signal), false);
inspect_fn = previous_inspect_fn; inspect_fn = previous_inspect_fn;
} else { } else {
update_derived(/** @type {import('./types.js').ComputationSignal<V>} **/ (signal), false); update_derived(/** @type {import('./types.js').Derived} **/ (signal), false);
} }
} }
return signal.v; return signal.v;
@ -808,7 +801,7 @@ export function invalidate_inner_signals(fn) {
} }
/** /**
* @param {import('./types.js').ComputationSignal} signal * @param {import('./types.js').Reaction} signal
* @param {boolean} inert * @param {boolean} inert
* @param {Set<import('./types.js').Block>} [visited_blocks] * @param {Set<import('./types.js').Block>} [visited_blocks]
* @returns {void} * @returns {void}
@ -827,7 +820,7 @@ function mark_subtree_children_inert(signal, inert, visited_blocks) {
} }
/** /**
* @param {import('./types.js').ComputationSignal} signal * @param {import('./types.js').Reaction} signal
* @param {boolean} inert * @param {boolean} inert
* @param {Set<import('./types.js').Block>} [visited_blocks] * @param {Set<import('./types.js').Block>} [visited_blocks]
* @returns {void} * @returns {void}
@ -838,7 +831,7 @@ export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
if (is_already_inert !== inert) { if (is_already_inert !== inert) {
signal.f ^= INERT; signal.f ^= INERT;
if (!inert && (flags & IS_EFFECT) !== 0 && (flags & CLEAN) === 0) { if (!inert && (flags & IS_EFFECT) !== 0 && (flags & CLEAN) === 0) {
schedule_effect(/** @type {import('./types.js').EffectSignal} */ (signal), false); schedule_effect(/** @type {import('./types.js').Effect} */ (signal), false);
} }
// Nested if block effects // Nested if block effects
const block = signal.b; const block = signal.b;
@ -901,7 +894,7 @@ export function mark_signal_consumers(signal, to_status, force_schedule) {
const maybe_dirty = (flags & MAYBE_DIRTY) !== 0; const maybe_dirty = (flags & MAYBE_DIRTY) !== 0;
if ((flags & CLEAN) !== 0 || (maybe_dirty && unowned)) { if ((flags & CLEAN) !== 0 || (maybe_dirty && unowned)) {
if ((consumer.f & IS_EFFECT) !== 0) { if ((consumer.f & IS_EFFECT) !== 0) {
schedule_effect(/** @type {import('./types.js').EffectSignal} */ (consumer), false); schedule_effect(/** @type {import('./types.js').Effect} */ (consumer), false);
} else { } else {
mark_signal_consumers(consumer, MAYBE_DIRTY, force_schedule); mark_signal_consumers(consumer, MAYBE_DIRTY, force_schedule);
} }
@ -911,8 +904,7 @@ export function mark_signal_consumers(signal, to_status, force_schedule) {
} }
/** /**
* @template V * @param {import('./types.js').Reaction} signal
* @param {import('./types.js').ComputationSignal<V>} signal
* @returns {void} * @returns {void}
*/ */
export function destroy_signal(signal) { export function destroy_signal(signal) {
@ -954,8 +946,7 @@ export function untrack(fn) {
} }
/** /**
* @template V * @param {import('./types.js').Reaction} signal
* @param {import('./types.js').ComputationSignal<V>} signal
* @param {() => void} destroy_fn * @param {() => void} destroy_fn
* @returns {void} * @returns {void}
*/ */
@ -1104,7 +1095,7 @@ function get_parent_context(component_context) {
} }
/** /**
* @param {import('./types.js').Signal<number>} signal * @param {import('./types.js').Value<number>} signal
* @param {1 | -1} [d] * @param {1 | -1} [d]
* @returns {number} * @returns {number}
*/ */
@ -1115,7 +1106,7 @@ export function update(signal, d = 1) {
} }
/** /**
* @param {import('./types.js').Signal<number>} signal * @param {import('./types.js').Value<number>} signal
* @param {1 | -1} [d] * @param {1 | -1} [d]
* @returns {number} * @returns {number}
*/ */

@ -295,7 +295,7 @@ const linear = (t) => t;
* @param {HTMLElement} dom * @param {HTMLElement} dom
* @param {() => import('./types.js').TransitionPayload} init * @param {() => import('./types.js').TransitionPayload} init
* @param {'in' | 'out' | 'both' | 'key'} direction * @param {'in' | 'out' | 'both' | 'key'} direction
* @param {import('./types.js').EffectSignal} effect * @param {import('./types.js').Effect} effect
* @returns {import('./types.js').Transition} * @returns {import('./types.js').Transition}
*/ */
function create_transition(dom, init, direction, effect) { function create_transition(dom, init, direction, effect) {
@ -503,7 +503,7 @@ function is_transition_block(block) {
* @returns {void} * @returns {void}
*/ */
export function bind_transition(dom, get_transition_fn, props_fn, direction, global) { export function bind_transition(dom, get_transition_fn, props_fn, direction, global) {
const transition_effect = /** @type {import('./types.js').EffectSignal} */ (current_effect); const transition_effect = /** @type {import('./types.js').Effect} */ (current_effect);
const block = current_block; const block = current_block;
const is_keyed_transition = direction === 'key'; const is_keyed_transition = direction === 'key';
@ -692,7 +692,7 @@ function if_block_transition(transition) {
// If the block has changed to falsy and has transitions // If the block has changed to falsy and has transitions
if (!block.v && c.size === 0) { if (!block.v && c.size === 0) {
const consequent_effect = block.ce; const consequent_effect = block.ce;
execute_effect(/** @type {import('./types.js').EffectSignal} */ (consequent_effect)); execute_effect(/** @type {import('./types.js').Effect} */ (consequent_effect));
} }
}); });
} else { } else {
@ -704,7 +704,7 @@ function if_block_transition(transition) {
// If the block has changed to truthy and has transitions // If the block has changed to truthy and has transitions
if (block.v && a.size === 0) { if (block.v && a.size === 0) {
const alternate_effect = block.ae; const alternate_effect = block.ae;
execute_effect(/** @type {import('./types.js').EffectSignal} */ (alternate_effect)); execute_effect(/** @type {import('./types.js').Effect} */ (alternate_effect));
} }
}); });
} }

@ -11,7 +11,7 @@ import {
SNIPPET_BLOCK, SNIPPET_BLOCK,
STATE_SYMBOL STATE_SYMBOL
} from './constants.js'; } from './constants.js';
import type { ComputationSignal, EffectSignal, Signal, SourceSignal } from './reactivity/types.js'; import type { Reaction, Effect, Signal, Source, Value } from './reactivity/types.js';
type EventCallback = (event: Event) => boolean; type EventCallback = (event: Event) => boolean;
export type EventCallbackMap = Record<string, EventCallback | EventCallback[]>; export type EventCallbackMap = Record<string, EventCallback | EventCallback[]>;
@ -33,7 +33,7 @@ export type ComponentContext = {
/** exports (and props, if `accessors: true`) */ /** exports (and props, if `accessors: true`) */
x: Record<string, any> | null; x: Record<string, any> | null;
/** effects */ /** effects */
e: null | Array<EffectSignal>; e: null | Array<Effect>;
/** mounted */ /** mounted */
m: boolean; m: boolean;
/** parent */ /** parent */
@ -71,7 +71,7 @@ export type TemplateNode = Text | Element | Comment;
export type Transition = { export type Transition = {
/** effect */ /** effect */
e: EffectSignal; e: Effect;
/** payload */ /** payload */
p: null | TransitionPayload; p: null | TransitionPayload;
/** init */ /** init */
@ -95,7 +95,7 @@ export type RootBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** intro */ /** intro */
i: boolean; i: boolean;
/** parent */ /** parent */
@ -112,7 +112,7 @@ export type IfBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | EffectSignal; e: null | Effect;
/** parent */ /** parent */
p: Block; p: Block;
/** transition */ /** transition */
@ -122,9 +122,9 @@ export type IfBlock = {
/** alternate transitions */ /** alternate transitions */
a: null | Set<Transition>; a: null | Set<Transition>;
/** effect */ /** effect */
ce: null | EffectSignal; ce: null | Effect;
/** effect */ /** effect */
ae: null | EffectSignal; ae: null | Effect;
/** type */ /** type */
t: typeof IF_BLOCK; t: typeof IF_BLOCK;
}; };
@ -133,7 +133,7 @@ export type KeyBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | EffectSignal; e: null | Effect;
/** parent */ /** parent */
p: Block; p: Block;
/** transition */ /** transition */
@ -146,7 +146,7 @@ export type HeadBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** parent */ /** parent */
p: Block; p: Block;
/** transition */ /** transition */
@ -159,7 +159,7 @@ export type DynamicElementBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** parent */ /** parent */
p: Block; p: Block;
/** transition */ /** transition */
@ -172,7 +172,7 @@ export type DynamicComponentBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** parent */ /** parent */
p: Block; p: Block;
/** transition */ /** transition */
@ -185,7 +185,7 @@ export type AwaitBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** parent */ /** parent */
p: Block; p: Block;
/** pending */ /** pending */
@ -206,7 +206,7 @@ export type EachBlock = {
/** items */ /** items */
v: EachItemBlock[]; v: EachItemBlock[];
/** effewct */ /** effewct */
e: null | ComputationSignal; e: null | Reaction;
/** parent */ /** parent */
p: Block; p: Block;
/** transition */ /** transition */
@ -223,11 +223,11 @@ export type EachItemBlock = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** item */ /** item */
v: any | Signal<any>; v: any | Value<any>;
/** index */ /** index */
i: number | Signal<number>; i: number | Value<number>;
/** key */ /** key */
k: unknown; k: unknown;
/** parent */ /** parent */
@ -246,7 +246,7 @@ export type SnippetBlock = {
/** parent */ /** parent */
p: Block; p: Block;
/** effect */ /** effect */
e: null | ComputationSignal; e: null | Reaction;
/** transition */ /** transition */
r: null; r: null;
/** type */ /** type */
@ -292,7 +292,7 @@ export type StoreReferencesContainer = Record<
store: Store<any> | null; store: Store<any> | null;
last_value: any; last_value: any;
unsubscribe: Function; unsubscribe: Function;
value: Signal<any>; value: Value<any>;
} }
>; >;
@ -302,7 +302,7 @@ export type Render = {
/** dom */ /** dom */
d: null | TemplateNode | Array<TemplateNode>; d: null | TemplateNode | Array<TemplateNode>;
/** effect */ /** effect */
e: null | EffectSignal; e: null | Effect;
/** transitions */ /** transitions */
s: Set<Transition>; s: Set<Transition>;
/** prev */ /** prev */
@ -325,9 +325,9 @@ export type TaskEntry = { c: TaskCallback; f: () => void };
export interface ProxyMetadata<T = Record<string | symbol, any>> { export interface ProxyMetadata<T = Record<string | symbol, any>> {
/** A map of signals associated to the properties that are reactive */ /** A map of signals associated to the properties that are reactive */
s: Map<string | symbol, SourceSignal<any>>; s: Map<string | symbol, Source<any>>;
/** A version counter, used within the proxy to signal changes in places where there's no other way to signal an update */ /** A version counter, used within the proxy to signal changes in places where there's no other way to signal an update */
v: SourceSignal<number>; v: Source<number>;
/** `true` if the proxified object is an array */ /** `true` if the proxified object is an array */
a: boolean; a: boolean;
/** Immutable: Whether to use a source or mutable source under the hood */ /** Immutable: Whether to use a source or mutable source under the hood */

@ -3,7 +3,7 @@ import * as $ from '../../src/internal/client/runtime';
import { derived } from '../../src/internal/client/reactivity/deriveds'; import { derived } from '../../src/internal/client/reactivity/deriveds';
import { effect, render_effect, user_effect } from '../../src/internal/client/reactivity/effects'; import { effect, render_effect, user_effect } from '../../src/internal/client/reactivity/effects';
import { source, set } from '../../src/internal/client/reactivity/sources'; import { source, set } from '../../src/internal/client/reactivity/sources';
import type { ComputationSignal } from '../../src/internal/client/types'; import type { Derived } from '../../src/internal/client/types';
import { proxy } from '../../src/internal/client/proxy'; import { proxy } from '../../src/internal/client/proxy';
/** /**
@ -206,7 +206,7 @@ describe('signals', () => {
test('correctly cleanup onowned nested derived values', () => { test('correctly cleanup onowned nested derived values', () => {
return () => { return () => {
const nested: ComputationSignal<string>[] = []; const nested: Derived<string>[] = [];
const a = source(0); const a = source(0);
const b = source(0); const b = source(0);

Loading…
Cancel
Save